diff --git a/.github/.gitleaks.toml b/.github/.gitleaks.toml deleted file mode 100644 index 009f1c613..000000000 --- a/.github/.gitleaks.toml +++ /dev/null @@ -1,546 +0,0 @@ -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.*''', '''.*:.*StrelkaHexDump.*''', '''.*:.*PLACEHOLDER.*''', '''ssl_.*password''', '''integration_key\s=\s"so-logs-"'''] -paths = [ - '''gitleaks.toml''', - '''(.*?)(jpg|gif|doc|pdf|bin|svg|socket)$''', - '''(go.mod|go.sum)$''', - '''salt/nginx/files/enterprise-attack.json''', - '''(.*?)whl$''' -] diff --git a/.github/DISCUSSION_TEMPLATE/2-4.yml b/.github/DISCUSSION_TEMPLATE/2-4.yml index 229e9f612..2755a536f 100644 --- a/.github/DISCUSSION_TEMPLATE/2-4.yml +++ b/.github/DISCUSSION_TEMPLATE/2-4.yml @@ -2,13 +2,11 @@ body: - type: markdown attributes: value: | - ⚠️ This category is solely for conversations related to Security Onion 2.4 ⚠️ - 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 2.4.x are you asking about? + description: Which version of Security Onion are you asking about? options: - - 2.4.10 @@ -33,6 +31,9 @@ body: - 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 @@ -94,7 +95,7 @@ body: attributes: label: Hardware Specs description: > - Does your hardware meet or exceed the minimum requirements for your installation type as shown at https://docs.securityonion.net/en/2.4/hardware.html? + 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 diff --git a/.github/DISCUSSION_TEMPLATE/3-0.yml b/.github/DISCUSSION_TEMPLATE/3-0.yml new file mode 100644 index 000000000..286ac823a --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/3-0.yml @@ -0,0 +1,177 @@ +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 + - 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 diff --git a/.github/workflows/leaktest.yml b/.github/workflows/leaktest.yml deleted file mode 100644 index fbe6c56e1..000000000 --- a/.github/workflows/leaktest.yml +++ /dev/null @@ -1,17 +0,0 @@ -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 diff --git a/.github/workflows/pythontest.yml b/.github/workflows/pythontest.yml index 21ed82ec2..a4cc92d8d 100644 --- a/.github/workflows/pythontest.yml +++ b/.github/workflows/pythontest.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.13"] + python-version: ["3.14"] python-code-path: ["salt/sensoroni/files/analyzers", "salt/manager/tools/sbin"] steps: diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index 30da22f2f..47937c1b9 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,46 +1,46 @@ -### 2.4.201-20260114 ISO image released on 2026/1/15 +### 3.0.0-20260331 ISO image released on 2026/03/31 ### Download and Verify -2.4.201-20260114 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-2.4.201-20260114.iso +3.0.0-20260331 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-3.0.0-20260331.iso -MD5: 20E926E433203798512EF46E590C89B9 -SHA1: 779E4084A3E1A209B494493B8F5658508B6014FA -SHA256: 3D10E7C885AEC5C5D4F4E50F9644FF9728E8C0A2E36EBB8C96B32569685A7C40 +MD5: ECD318A1662A6FDE0EF213F5A9BD4B07 +SHA1: E55BE314440CCF3392DC0B06BC5E270B43176D9C +SHA256: 7FC47405E335CBE5C2B6C51FE7AC60248F35CBE504907B8B5A33822B23F8F4D5 Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.201-20260114.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.0.0-20260331.iso.sig Signing key: -https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS +https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/3/main/KEYS 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: ``` -wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS -O - | gpg --import - +wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/3/main/KEYS -O - | gpg --import - ``` Download the signature file for the ISO: ``` -wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.201-20260114.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/3/main/sigs/securityonion-3.0.0-20260331.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-2.4.201-20260114.iso +wget https://download.securityonion.net/file/securityonion/securityonion-3.0.0-20260331.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-2.4.201-20260114.iso.sig securityonion-2.4.201-20260114.iso +gpg --verify securityonion-3.0.0-20260331.iso.sig securityonion-3.0.0-20260331.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Wed 14 Jan 2026 05:23:39 PM EST using RSA key ID FE507013 +gpg: Signature made Mon 30 Mar 2026 06:22:14 PM EDT using RSA key ID FE507013 gpg: Good signature from "Security Onion Solutions, LLC " gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. @@ -50,4 +50,4 @@ 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: -https://docs.securityonion.net/en/2.4/installation.html +https://securityonion.net/docs/installation diff --git a/README.md b/README.md index 530a21813..6eeb77ec3 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,58 @@ -## Security Onion 2.4 +

+ Security Onion Logo +

-Security Onion 2.4 is here! +# Security Onion -## Screenshots +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. -Alerts -![Alerts](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/50_alerts.png) +## ✨ Features -Dashboards -![Dashboards](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/53_dashboards.png) +Security Onion includes everything you need to monitor your network and host systems: -Hunt -![Hunt](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/56_hunt.png) +* **Security Onion Console (SOC)**: A unified web interface for analyzing security events and managing your grid. +* **Elastic Stack**: Powerful search backed by Elasticsearch. +* **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. -Detections -![Detections](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/57_detections.png) +## ⭐ Security Onion Pro -PCAP -![PCAP](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/62_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/75_grid.png) +* **Onion AI**: Leverage powerful AI-driven insights to accelerate your analysis and investigations. +* **Enterprise Features**: Enhanced tools and integrations tailored for enterprise-grade security operations. -Config -![Config](https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion-docs/2.4/images/87_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** | [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) | -### Download +## 📖 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) +* **Community**: [Discussions & Support](https://securityonion.net/docs/community-support) +* **Training**: [Official Training](https://securityonion.net/training) -https://docs.securityonion.net/en/2.4/installation.html +## 🤝 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.* diff --git a/SECURITY.md b/SECURITY.md index 5001e4cd0..a8a73469c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,6 +4,7 @@ | Version | Supported | | ------- | ------------------ | +| 3.x | :white_check_mark: | | 2.4.x | :white_check_mark: | | 2.3.x | :x: | | 16.04.x | :x: | diff --git a/VERSION b/VERSION index a16ed1915..4a36342fc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -UNRELEASED +3.0.0 diff --git a/pillar/ca/init.sls b/pillar/ca/init.sls new file mode 100644 index 000000000..7d1ea9702 --- /dev/null +++ b/pillar/ca/init.sls @@ -0,0 +1,2 @@ +ca: + server: diff --git a/pillar/top.sls b/pillar/top.sls index d25aeecfa..6cdc4808a 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,5 +1,6 @@ base: '*': + - ca - global.soc_global - global.adv_global - docker.soc_docker @@ -86,8 +87,6 @@ base: - zeek.adv_zeek - bpf.soc_bpf - bpf.adv_bpf - - pcap.soc_pcap - - pcap.adv_pcap - suricata.soc_suricata - suricata.adv_suricata - minions.{{ grains.id }} @@ -133,8 +132,6 @@ base: - zeek.adv_zeek - bpf.soc_bpf - bpf.adv_bpf - - pcap.soc_pcap - - pcap.adv_pcap - suricata.soc_suricata - suricata.adv_suricata - minions.{{ grains.id }} @@ -184,8 +181,6 @@ base: - zeek.adv_zeek - bpf.soc_bpf - bpf.adv_bpf - - pcap.soc_pcap - - pcap.adv_pcap - suricata.soc_suricata - suricata.adv_suricata - minions.{{ grains.id }} @@ -208,8 +203,6 @@ base: - zeek.adv_zeek - bpf.soc_bpf - bpf.adv_bpf - - pcap.soc_pcap - - pcap.adv_pcap - suricata.soc_suricata - suricata.adv_suricata - strelka.soc_strelka @@ -296,8 +289,6 @@ base: - zeek.adv_zeek - bpf.soc_bpf - bpf.adv_bpf - - pcap.soc_pcap - - pcap.adv_pcap - suricata.soc_suricata - suricata.adv_suricata - strelka.soc_strelka diff --git a/salt/_modules/needs_restarting.py b/salt/_modules/needs_restarting.py index edede9ad3..23000cac6 100644 --- a/salt/_modules/needs_restarting.py +++ b/salt/_modules/needs_restarting.py @@ -1,24 +1,14 @@ -from os import path import subprocess def check(): - osfam = __grains__['os_family'] retval = 'False' - if osfam == 'Debian': - if path.exists('/var/run/reboot-required'): - retval = 'True' + cmd = 'needs-restarting -r > /dev/null 2>&1' - elif osfam == 'RedHat': - cmd = 'needs-restarting -r > /dev/null 2>&1' - - try: - needs_restarting = subprocess.check_call(cmd, shell=True) - except subprocess.CalledProcessError: - retval = 'True' - - else: - retval = 'Unsupported OS: %s' % os + try: + needs_restarting = subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError: + retval = 'True' return retval diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 2393f92d7..1fac0f0e3 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -15,11 +15,7 @@ 'salt.minion-check', 'sensoroni', 'salt.lasthighstate', - 'salt.minion' -] %} - -{% set ssl_states = [ - 'ssl', + 'salt.minion', 'telegraf', 'firewall', 'schedule', @@ -28,7 +24,7 @@ {% set manager_states = [ 'salt.master', - 'ca', + 'ca.server', 'registry', 'manager', 'nginx', @@ -42,7 +38,6 @@ ] %} {% set sensor_states = [ - 'pcap', 'suricata', 'healthcheck', 'tcpreplay', @@ -75,28 +70,24 @@ {# Map role-specific states #} {% set role_states = { 'so-eval': ( - ssl_states + manager_states + sensor_states + - elastic_stack_states | reject('equalto', 'logstash') | list + elastic_stack_states | reject('equalto', 'logstash') | list + + ['logstash.ssl'] ), 'so-heavynode': ( - ssl_states + sensor_states + ['elasticagent', 'elasticsearch', 'logstash', 'redis', 'nginx'] ), 'so-idh': ( - ssl_states + ['idh'] ), 'so-import': ( - ssl_states + manager_states + sensor_states | reject('equalto', 'strelka') | reject('equalto', 'healthcheck') | list + - ['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets', 'strelka.manager'] + ['elasticsearch', 'elasticsearch.auth', 'kibana', 'kibana.secrets', 'logstash.ssl', 'strelka.manager'] ), 'so-manager': ( - ssl_states + manager_states + ['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] + stig_states + @@ -104,7 +95,6 @@ elastic_stack_states ), 'so-managerhype': ( - ssl_states + manager_states + ['salt.cloud', 'strelka.manager', 'hypervisor', 'libvirt'] + stig_states + @@ -112,7 +102,6 @@ elastic_stack_states ), 'so-managersearch': ( - ssl_states + manager_states + ['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users', 'strelka.manager'] + stig_states + @@ -120,12 +109,10 @@ elastic_stack_states ), 'so-searchnode': ( - ssl_states + ['kafka.ca', 'kafka.ssl', 'elasticsearch', 'logstash', 'nginx'] + stig_states ), 'so-standalone': ( - ssl_states + manager_states + ['salt.cloud', 'libvirt.packages', 'libvirt.ssh.users'] + sensor_states + @@ -134,29 +121,24 @@ elastic_stack_states ), 'so-sensor': ( - ssl_states + sensor_states + ['nginx'] + stig_states ), 'so-fleet': ( - ssl_states + stig_states + ['logstash', 'nginx', 'healthcheck', 'elasticfleet'] ), 'so-receiver': ( - ssl_states + kafka_states + stig_states + ['logstash', 'redis'] ), 'so-hypervisor': ( - ssl_states + stig_states + ['hypervisor', 'libvirt'] ), 'so-desktop': ( - ['ssl', 'docker_clean', 'telegraf'] + stig_states ) } %} diff --git a/salt/backup/soc_backup.yaml b/salt/backup/soc_backup.yaml index bedecb1ca..87ce2551e 100644 --- a/salt/backup/soc_backup.yaml +++ b/salt/backup/soc_backup.yaml @@ -1,10 +1,10 @@ backup: locations: description: List of locations to back up to the destination. - helpLink: backup.html + helpLink: backup global: True destination: description: Directory to store the configuration backups in. - helpLink: backup.html + helpLink: backup global: True \ No newline at end of file diff --git a/salt/bpf/macros.jinja b/salt/bpf/macros.jinja index 38cb8ed0d..1fcb1af7c 100644 --- a/salt/bpf/macros.jinja +++ b/salt/bpf/macros.jinja @@ -1,10 +1,12 @@ {% macro remove_comments(bpfmerged, app) %} {# remove comments from the bpf #} +{% set app_list = [] %} {% for bpf in bpfmerged[app] %} -{% if bpf.strip().startswith('#') %} -{% do bpfmerged[app].pop(loop.index0) %} +{% if not bpf.strip().startswith('#') %} +{% do app_list.append(bpf) %} {% endif %} {% endfor %} +{% do bpfmerged.update({app: app_list}) %} {% endmacro %} diff --git a/salt/bpf/pcap.map.jinja b/salt/bpf/pcap.map.jinja index 953b01a08..e6108a0cb 100644 --- a/salt/bpf/pcap.map.jinja +++ b/salt/bpf/pcap.map.jinja @@ -1,21 +1,15 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} {% set PCAP_BPF_STATUS = 0 %} -{% set STENO_BPF_COMPILED = "" %} -{% if GLOBALS.pcap_engine == "TRANSITION" %} -{% set PCAPBPF = ["ip and host 255.255.255.1 and port 1"] %} -{% else %} {% import_yaml 'bpf/defaults.yaml' as BPFDEFAULTS %} {% set BPFMERGED = salt['pillar.get']('bpf', BPFDEFAULTS.bpf, merge=True) %} {% import 'bpf/macros.jinja' as MACROS %} {{ MACROS.remove_comments(BPFMERGED, 'pcap') }} {% set PCAPBPF = BPFMERGED.pcap %} -{% endif %} {% if PCAPBPF %} - {% set PCAP_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ PCAPBPF|join(" "), cwd='/root') %} + {% 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 PCAP_BPF_STATUS = 1 %} - {% set STENO_BPF_COMPILED = ",\\\"--filter=" + PCAP_BPF_CALC['stdout'] + "\\\"" %} {% endif %} {% endif %} diff --git a/salt/bpf/soc_bpf.yaml b/salt/bpf/soc_bpf.yaml index 416c5fc60..5d3af93fb 100644 --- a/salt/bpf/soc_bpf.yaml +++ b/salt/bpf/soc_bpf.yaml @@ -3,14 +3,14 @@ bpf: description: List of BPF filters to apply to the PCAP engine. multiline: True forcedType: "[]string" - helpLink: bpf.html + helpLink: bpf 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. multiline: True forcedType: "[]string" - helpLink: bpf.html + helpLink: bpf zeek: description: List of BPF filters to apply to Zeek. multiline: True forcedType: "[]string" - helpLink: bpf.html + helpLink: bpf diff --git a/salt/bpf/suricata.map.jinja b/salt/bpf/suricata.map.jinja index 5ee1e5a92..0fdefd280 100644 --- a/salt/bpf/suricata.map.jinja +++ b/salt/bpf/suricata.map.jinja @@ -9,7 +9,7 @@ {% set SURICATABPF = BPFMERGED.suricata %} {% if SURICATABPF %} - {% set SURICATA_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ SURICATABPF|join(" "), cwd='/root') %} + {% 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 %} diff --git a/salt/bpf/zeek.map.jinja b/salt/bpf/zeek.map.jinja index 789648bdb..ac067bbe8 100644 --- a/salt/bpf/zeek.map.jinja +++ b/salt/bpf/zeek.map.jinja @@ -9,7 +9,7 @@ {% set ZEEKBPF = BPFMERGED.zeek %} {% if ZEEKBPF %} - {% set ZEEK_BPF_CALC = salt['cmd.run_all']('/usr/sbin/so-bpf-compile ' ~ GLOBALS.sensor.interface ~ ' ' ~ ZEEKBPF|join(" "), cwd='/root') %} + {% 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 %} diff --git a/salt/ca/dirs.sls b/salt/ca/dirs.sls deleted file mode 100644 index 36f37b760..000000000 --- a/salt/ca/dirs.sls +++ /dev/null @@ -1,4 +0,0 @@ -pki_issued_certs: - file.directory: - - name: /etc/pki/issued_certs - - makedirs: True diff --git a/salt/ca/init.sls b/salt/ca/init.sls index 895e8235a..3a0fdf91c 100644 --- a/salt/ca/init.sls +++ b/salt/ca/init.sls @@ -3,70 +3,10 @@ # 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 %} - include: - - ca.dirs - -/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 - +{% if GLOBALS.is_manager %} + - ca.server {% endif %} + - ca.trustca diff --git a/salt/ca/map.jinja b/salt/ca/map.jinja new file mode 100644 index 000000000..87641198d --- /dev/null +++ b/salt/ca/map.jinja @@ -0,0 +1,3 @@ +{% set CA = { + 'server': pillar.ca.server +}%} diff --git a/salt/ca/remove.sls b/salt/ca/remove.sls index 3af355951..181702b01 100644 --- a/salt/ca/remove.sls +++ b/salt/ca/remove.sls @@ -1,7 +1,35 @@ -pki_private_key: +# 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 setup_running = salt['cmd.retcode']('pgrep -x so-setup') == 0 %} + +{% if setup_running%} + +include: + - ssl.remove + +remove_pki_private_key: file.absent: - name: /etc/pki/ca.key -pki_public_ca_crt: +remove_pki_public_ca_crt: file.absent: - 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 %} diff --git a/salt/ca/server.sls b/salt/ca/server.sls new file mode 100644 index 000000000..474e7c9fd --- /dev/null +++ b/salt/ca/server.sls @@ -0,0 +1,63 @@ +# 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 %} diff --git a/salt/pcap/tools/sbin/so-pcap-export b/salt/ca/signing_policy.sls old mode 100755 new mode 100644 similarity index 51% rename from salt/pcap/tools/sbin/so-pcap-export rename to salt/ca/signing_policy.sls index af7686028..5deea929a --- a/salt/pcap/tools/sbin/so-pcap-export +++ b/salt/ca/signing_policy.sls @@ -1,18 +1,15 @@ -#!/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. +# when the salt-minion signs the cert, a copy is stored here +issued_certs_copypath: + file.directory: + - name: /etc/pki/issued_certs + - makedirs: True - -if [ $# -lt 2 ]; then - echo "Usage: $0 Output-Filename" - exit 1 -fi - -docker exec -t so-sensoroni scripts/stenoquery.sh "$1" -w /nsm/pcapout/$2.pcap - -echo "" -echo "If successful, the output was written to: /nsm/pcapout/$2.pcap" +signing_policy: + file.managed: + - name: /etc/salt/minion.d/signing_policies.conf + - source: salt://ca/files/signing_policies.conf diff --git a/salt/pcap/tools/sbin/so-pcap-restart b/salt/ca/trustca.sls old mode 100755 new mode 100644 similarity index 56% rename from salt/pcap/tools/sbin/so-pcap-restart rename to salt/ca/trustca.sls index a35ed5aa2..33124389f --- a/salt/pcap/tools/sbin/so-pcap-restart +++ b/salt/ca/trustca.sls @@ -1,12 +1,18 @@ -#!/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. +include: + - docker +# Trust the CA +trusttheca: + file.managed: + - name: /etc/pki/tls/certs/intca.crt + - source: salt://ca/files/ca.crt + - watch_in: + - service: docker_running + - show_changes: False + - makedirs: True -. /usr/sbin/so-common - -/usr/sbin/so-restart steno $1 diff --git a/salt/common/files/daemon.json b/salt/common/files/daemon.json deleted file mode 100644 index 32d1fc1fe..000000000 --- a/salt/common/files/daemon.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "registry-mirrors": [ - "https://:5000" - ], - "bip": "172.17.0.1/24", - "default-address-pools": [ - { - "base": "172.17.0.0/24", - "size": 24 - } - ] -} diff --git a/salt/common/init.sls b/salt/common/init.sls index eba18f651..120e73e3e 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -20,11 +20,6 @@ kernel.printk: sysctl.present: - value: "3 4 1 3" -# Remove variables.txt from /tmp - This is temp -rmvariablesfile: - file.absent: - - name: /tmp/variables.txt - # Add socore Group socoregroup: group.present: @@ -149,35 +144,13 @@ common_sbin_jinja: - so-import-pcap {% endif %} -{% if GLOBALS.role == 'so-heavynode' %} -remove_so-pcap-import_heavynode: - file.absent: - - name: /usr/sbin/so-pcap-import - -remove_so-import-pcap_heavynode: - file.absent: - - name: /usr/sbin/so-import-pcap -{% endif %} - -{% if not GLOBALS.is_manager%} -# prior to 2.4.50 these scripts were in common/tools/sbin on the manager because of soup and distributed to non managers -# these two states remove the scripts from non manager nodes -remove_soup: - file.absent: - - name: /usr/sbin/soup - -remove_so-firewall: - file.absent: - - name: /usr/sbin/so-firewall -{% endif %} - so-status_script: file.managed: - name: /usr/sbin/so-status - source: salt://common/tools/sbin/so-status - mode: 755 -{% if GLOBALS.role in GLOBALS.sensor_roles %} +{% if GLOBALS.is_sensor %} # Add sensor cleanup so-sensor-clean: cron.present: diff --git a/salt/common/packages.sls b/salt/common/packages.sls index cd8af4bb0..cdae393d0 100644 --- a/salt/common/packages.sls +++ b/salt/common/packages.sls @@ -1,52 +1,5 @@ # we cannot import GLOBALS from vars/globals.map.jinja in this state since it is called in setup.virt.init # since it is early in setup of a new VM, the pillars imported in GLOBALS are not yet defined -{% if grains.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 - - bc - {% 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 grains.os_family == 'RedHat' %} remove_mariadb: pkg.removed: @@ -84,5 +37,3 @@ commonpkgs: - unzip - wget - yum-utils - -{% endif %} diff --git a/salt/common/soup_scripts.sls b/salt/common/soup_scripts.sls index 24e6c6152..6b2f1551d 100644 --- a/salt/common/soup_scripts.sls +++ b/salt/common/soup_scripts.sls @@ -3,8 +3,6 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% if '2.4' in salt['cp.get_file_str']('/etc/soversion') %} - {% import_yaml '/opt/so/saltstack/local/pillar/global/soc_global.sls' as SOC_GLOBAL %} {% if SOC_GLOBAL.global.airgap %} {% set UPDATE_DIR='/tmp/soagupdate/SecurityOnion' %} @@ -13,14 +11,6 @@ {% endif %} {% set SOVERSION = salt['file.read']('/etc/soversion').strip() %} -remove_common_soup: - file.absent: - - name: /opt/so/saltstack/default/salt/common/tools/sbin/soup - -remove_common_so-firewall: - file.absent: - - name: /opt/so/saltstack/default/salt/common/tools/sbin/so-firewall - # This section is used to put the scripts in place in the Salt file system # in case a state run tries to overwrite what we do in the next section. copy_so-common_common_tools_sbin: @@ -120,23 +110,3 @@ copy_bootstrap-salt_sbin: - source: {{UPDATE_DIR}}/salt/salt/scripts/bootstrap-salt.sh - force: True - preserve: True - -{# this is added in 2.4.120 to remove salt repo files pointing to saltproject.io to accomodate the move to broadcom and new bootstrap-salt script #} -{% if salt['pkg.version_cmp'](SOVERSION, '2.4.120') == -1 %} -{% set saltrepofile = '/etc/yum.repos.d/salt.repo' %} -{% if grains.os_family == 'Debian' %} -{% set saltrepofile = '/etc/apt/sources.list.d/salt.list' %} -{% endif %} -remove_saltproject_io_repo_manager: - file.absent: - - name: {{ saltrepofile }} -{% endif %} - -{% else %} -fix_23_soup_sbin: - cmd.run: - - name: curl -s -f -o /usr/sbin/soup https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.3/main/salt/common/tools/sbin/soup -fix_23_soup_salt: - cmd.run: - - name: curl -s -f -o /opt/so/saltstack/defalt/salt/common/tools/sbin/soup https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.3/main/salt/common/tools/sbin/soup -{% endif %} diff --git a/salt/common/tools/sbin/so-bpf-compile b/salt/common/tools/sbin/so-bpf-compile index 316a26775..a9d2c7850 100755 --- a/salt/common/tools/sbin/so-bpf-compile +++ b/salt/common/tools/sbin/so-bpf-compile @@ -16,7 +16,7 @@ if [ "$#" -lt 2 ]; then cat 1>&2 < /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() { cat /proc/net/bonding/bond0 | grep "Slave Interface:" | sed -e "s/Slave Interface: //g" } @@ -531,6 +545,22 @@ retry() { 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() { local cmd=$1 local err_msg=${2:-"Unknown error occured, please check /root/$WHATWOULDYOUSAYYAHDOHERE.log for details."} # Really need to rename that variable @@ -554,21 +584,39 @@ run_check_net_err() { } wait_for_salt_minion() { - local minion="$1" - local timeout="${2:-5}" - local logfile="${3:-'/dev/stdout'}" - retry 60 5 "journalctl -u salt-minion.service | grep 'Minion is ready to receive requests'" >> "$logfile" 2>&1 || fail - local attempt=0 - # each attempts would take about 15 seconds - local maxAttempts=20 - until check_salt_minion_status "$minion" "$timeout" "$logfile"; do - attempt=$((attempt+1)) - if [[ $attempt -eq $maxAttempts ]]; then - return 1 - fi - sleep 10 - done - return 0 + local minion="$1" + local max_wait="${2:-30}" + local interval="${3:-2}" + local logfile="${4:-'/dev/stdout'}" + local elapsed=0 + + echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - Waiting for salt-minion '$minion' to be ready..." + + while [ $elapsed -lt $max_wait ]; do + # Check if service is running + 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 } salt_minion_count() { @@ -578,69 +626,19 @@ salt_minion_count() { } set_os() { - 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 - OSVER=9 - is_oracle=true - is_rpm=true - else - OS=rhel - OSVER=9 - is_rhel=true - is_rpm=true - fi - fi - 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" + if [ -f /etc/redhat-release ] && grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release && [ -f /etc/oracle-release ]; then + OS=oracle + OSVER=9 + is_oracle=true + is_rpm=true fi + cron_service_name="crond" } set_minionid() { MINIONID=$(lookup_grain id) } -set_palette() { - if [[ $is_deb ]]; then - update-alternatives --set newt-palette /etc/newt/palette.original - fi -} set_version() { CURRENTVERSION=0.0.0 diff --git a/salt/common/tools/sbin/so-image-common b/salt/common/tools/sbin/so-image-common index 4358e6d00..5ce2da241 100755 --- a/salt/common/tools/sbin/so-image-common +++ b/salt/common/tools/sbin/so-image-common @@ -32,7 +32,6 @@ container_list() { "so-nginx" "so-pcaptools" "so-soc" - "so-steno" "so-suricata" "so-telegraf" "so-zeek" @@ -58,7 +57,6 @@ container_list() { "so-pcaptools" "so-redis" "so-soc" - "so-steno" "so-strelka-backend" "so-strelka-manager" "so-suricata" @@ -71,7 +69,6 @@ container_list() { "so-logstash" "so-nginx" "so-redis" - "so-steno" "so-suricata" "so-soc" "so-telegraf" diff --git a/salt/common/tools/sbin/so-log-check b/salt/common/tools/sbin/so-log-check index 5960a7946..8c8bbf35c 100755 --- a/salt/common/tools/sbin/so-log-check +++ b/salt/common/tools/sbin/so-log-check @@ -129,6 +129,9 @@ if [[ $EXCLUDE_STARTUP_ERRORS == 'Y' ]]; then 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 if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then @@ -159,7 +162,9 @@ if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then 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 if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then @@ -175,7 +180,6 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then 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|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|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|error parsing signature" # Malformed Suricata rule, from upstream provider EXCLUDED_ERRORS="$EXCLUDED_ERRORS|sticky buffer has no matches" # Non-critical Suricata error @@ -223,6 +227,8 @@ if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then 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 RESULT=0 diff --git a/salt/common/tools/sbin/so-nsm-clear b/salt/common/tools/sbin/so-nsm-clear index c9e5e86d2..873ce9f3a 100755 --- a/salt/common/tools/sbin/so-nsm-clear +++ b/salt/common/tools/sbin/so-nsm-clear @@ -55,19 +55,22 @@ if [ $SKIP -ne 1 ]; then fi delete_pcap() { - PCAP_DATA="/nsm/pcap/" - [ -d $PCAP_DATA ] && so-pcap-stop && rm -rf $PCAP_DATA/* && so-pcap-start + PCAP_DATA="/nsm/suripcap/" + [ -d $PCAP_DATA ] && rm -rf $PCAP_DATA/* } delete_suricata() { SURI_LOG="/nsm/suricata/" - [ -d $SURI_LOG ] && so-suricata-stop && rm -rf $SURI_LOG/* && so-suricata-start + [ -d $SURI_LOG ] && rm -rf $SURI_LOG/* } delete_zeek() { ZEEK_LOG="/nsm/zeek/logs/" [ -d $ZEEK_LOG ] && so-zeek-stop && rm -rf $ZEEK_LOG/* && so-zeek-start } +so-suricata-stop delete_pcap delete_suricata delete_zeek +so-suricata-start + diff --git a/salt/common/tools/sbin/so-restart b/salt/common/tools/sbin/so-restart index 8f73faee1..7345078b8 100755 --- a/salt/common/tools/sbin/so-restart +++ b/salt/common/tools/sbin/so-restart @@ -23,7 +23,6 @@ if [ $# -ge 1 ]; then fi 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;; *) docker stop so-$1 ; docker rm so-$1 ; salt-call state.apply $1 queue=True;; esac diff --git a/salt/common/tools/sbin/so-sensor-clean b/salt/common/tools/sbin/so-sensor-clean index 472663bb1..083a316b9 100755 --- a/salt/common/tools/sbin/so-sensor-clean +++ b/salt/common/tools/sbin/so-sensor-clean @@ -72,7 +72,7 @@ clean() { done fi - ## Clean up extracted pcaps from Steno + ## Clean up extracted pcaps PCAPS='/nsm/pcapout' 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 diff --git a/salt/common/tools/sbin/so-start b/salt/common/tools/sbin/so-start index b0d5780e2..1a312a94d 100755 --- a/salt/common/tools/sbin/so-start +++ b/salt/common/tools/sbin/so-start @@ -23,7 +23,6 @@ if [ $# -ge 1 ]; then case $1 in "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 ;; *) 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 diff --git a/salt/common/tools/sbin_jinja/so-desktop-install b/salt/common/tools/sbin_jinja/so-desktop-install index 6275bb3b6..774a8a118 100755 --- a/salt/common/tools/sbin_jinja/so-desktop-install +++ b/salt/common/tools/sbin_jinja/so-desktop-install @@ -6,7 +6,7 @@ # Elastic License 2.0. source /usr/sbin/so-common -doc_desktop_url="$DOC_BASE_URL/desktop.html" +doc_desktop_url="$DOC_BASE_URL/desktop" {# we only want the script to install the desktop if it is OEL -#} {% if grains.os == 'OEL' -%} diff --git a/salt/curator/disabled.sls b/salt/curator/disabled.sls deleted file mode 100644 index 07346aa02..000000000 --- a/salt/curator/disabled.sls +++ /dev/null @@ -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. - -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 %} \ No newline at end of file diff --git a/salt/desktop/trusted-ca.sls b/salt/desktop/trusted-ca.sls index 87fc70ef9..5117de1cd 100644 --- a/salt/desktop/trusted-ca.sls +++ b/salt/desktop/trusted-ca.sls @@ -3,29 +3,16 @@ {# we only want this state to run it is CentOS #} {% 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: - x509.pem_managed: + file.managed: - name: /etc/pki/ca-trust/source/anchors/ca.crt - - text: {{ trusttheca_text }} + - source: salt://ca/files/ca.crt update_ca_certs: cmd.run: - name: update-ca-trust - onchanges: - - x509: trusted_ca + - file: trusted_ca {% else %} diff --git a/salt/docker/defaults.yaml b/salt/docker/defaults.yaml index 456a187d6..044ec98b0 100644 --- a/salt/docker/defaults.yaml +++ b/salt/docker/defaults.yaml @@ -1,6 +1,10 @@ docker: range: '172.17.1.0/24' gateway: '172.17.1.1' + ulimits: + - name: nofile + soft: 1048576 + hard: 1048576 containers: 'so-dockerregistry': final_octet: 20 @@ -9,6 +13,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-elastic-fleet': final_octet: 21 port_bindings: @@ -16,6 +21,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-elasticsearch': final_octet: 22 port_bindings: @@ -24,6 +30,16 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: + - name: memlock + soft: -1 + hard: -1 + - name: nofile + soft: 65536 + hard: 65536 + - name: nproc + soft: 4096 + hard: 4096 'so-influxdb': final_octet: 26 port_bindings: @@ -31,6 +47,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-kibana': final_octet: 27 port_bindings: @@ -38,6 +55,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-kratos': final_octet: 28 port_bindings: @@ -46,6 +64,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-hydra': final_octet: 30 port_bindings: @@ -54,6 +73,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-logstash': final_octet: 29 port_bindings: @@ -70,6 +90,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-nginx': final_octet: 31 port_bindings: @@ -81,6 +102,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-nginx-fleet-node': final_octet: 31 port_bindings: @@ -88,6 +110,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-redis': final_octet: 33 port_bindings: @@ -96,11 +119,13 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-sensoroni': final_octet: 99 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-soc': final_octet: 34 port_bindings: @@ -108,16 +133,19 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-strelka-backend': final_octet: 36 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-strelka-filestream': final_octet: 37 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-strelka-frontend': final_octet: 38 port_bindings: @@ -125,11 +153,13 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-strelka-manager': final_octet: 39 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-strelka-gatekeeper': final_octet: 40 port_bindings: @@ -137,6 +167,7 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-strelka-coordinator': final_octet: 41 port_bindings: @@ -144,11 +175,13 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-elastalert': final_octet: 42 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-elastic-fleet-package-registry': final_octet: 44 port_bindings: @@ -156,11 +189,13 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-idh': final_octet: 45 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-elastic-agent': final_octet: 46 port_bindings: @@ -169,28 +204,28 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] 'so-telegraf': final_octet: 99 custom_bind_mounts: [] extra_hosts: [] extra_env: [] - 'so-steno': - final_octet: 99 - custom_bind_mounts: [] - extra_hosts: [] - extra_env: [] + ulimits: [] 'so-suricata': final_octet: 99 custom_bind_mounts: [] extra_hosts: [] extra_env: [] - ulimits: - - memlock=524288000 + ulimits: [] 'so-zeek': final_octet: 99 custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: + - name: core + soft: 0 + hard: 0 'so-kafka': final_octet: 88 port_bindings: @@ -201,3 +236,4 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + ulimits: [] diff --git a/salt/docker/docker.map.jinja b/salt/docker/docker.map.jinja index 61416f7a4..595d5d272 100644 --- a/salt/docker/docker.map.jinja +++ b/salt/docker/docker.map.jinja @@ -1,8 +1,8 @@ {% import_yaml 'docker/defaults.yaml' as DOCKERDEFAULTS %} -{% set DOCKER = salt['pillar.get']('docker', DOCKERDEFAULTS.docker, merge=True) %} -{% set RANGESPLIT = DOCKER.range.split('.') %} +{% set DOCKERMERGED = salt['pillar.get']('docker', DOCKERDEFAULTS.docker, merge=True) %} +{% set RANGESPLIT = DOCKERMERGED.range.split('.') %} {% set FIRSTTHREE = RANGESPLIT[0] ~ '.' ~ RANGESPLIT[1] ~ '.' ~ RANGESPLIT[2] ~ '.' %} -{% for container, vals in DOCKER.containers.items() %} -{% do DOCKER.containers[container].update({'ip': FIRSTTHREE ~ DOCKER.containers[container].final_octet}) %} +{% for container, vals in DOCKERMERGED.containers.items() %} +{% do DOCKERMERGED.containers[container].update({'ip': FIRSTTHREE ~ DOCKERMERGED.containers[container].final_octet}) %} {% endfor %} diff --git a/salt/docker/files/daemon.json.jinja b/salt/docker/files/daemon.json.jinja new file mode 100644 index 000000000..3f5e4c914 --- /dev/null +++ b/salt/docker/files/daemon.json.jinja @@ -0,0 +1,24 @@ +{% 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 %} +} diff --git a/salt/docker/init.sls b/salt/docker/init.sls index 5a0d1f61a..52091ed95 100644 --- a/salt/docker/init.sls +++ b/salt/docker/init.sls @@ -3,61 +3,27 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} -# include ssl since docker service requires the intca +# docker service requires the ca.crt include: - - ssl + - ca dockergroup: group.present: - name: docker - gid: 920 -{% if GLOBALS.os_family == 'Debian' %} -{% if grains.oscodename == 'bookworm' %} dockerheldpackages: pkg.installed: - pkgs: - - containerd.io: 1.7.21-1 - - docker-ce: 5:27.2.0-1~debian.12~bookworm - - docker-ce-cli: 5:27.2.0-1~debian.12~bookworm - - docker-ce-rootless-extras: 5:27.2.0-1~debian.12~bookworm + - containerd.io: 2.2.1-1.el9 + - docker-ce: 3:29.2.1-1.el9 + - docker-ce-cli: 1:29.2.1-1.el9 + - docker-ce-rootless-extras: 29.2.1-1.el9 - hold: True - update_holds: True -{% elif grains.oscodename == 'jammy' %} -dockerheldpackages: - pkg.installed: - - pkgs: - - containerd.io: 1.7.21-1 - - docker-ce: 5:27.2.0-1~ubuntu.22.04~jammy - - docker-ce-cli: 5:27.2.0-1~ubuntu.22.04~jammy - - docker-ce-rootless-extras: 5:27.2.0-1~ubuntu.22.04~jammy - - hold: True - - update_holds: True -{% else %} -dockerheldpackages: - pkg.installed: - - pkgs: - - containerd.io: 1.7.21-1 - - docker-ce: 5:27.2.0-1~ubuntu.20.04~focal - - docker-ce-cli: 5:27.2.0-1~ubuntu.20.04~focal - - docker-ce-rootless-extras: 5:27.2.0-1~ubuntu.20.04~focal - - hold: True - - update_holds: True -{% endif %} -{% else %} -dockerheldpackages: - pkg.installed: - - pkgs: - - containerd.io: 1.7.21-3.1.el9 - - docker-ce: 3:27.2.0-1.el9 - - docker-ce-cli: 1:27.2.0-1.el9 - - docker-ce-rootless-extras: 27.2.0-1.el9 - - hold: True - - update_holds: True -{% endif %} #disable docker from managing iptables iptables_disabled: @@ -75,10 +41,9 @@ dockeretc: file.directory: - name: /etc/docker -# Manager daemon.json docker_daemon: file.managed: - - source: salt://common/files/daemon.json + - source: salt://docker/files/daemon.json.jinja - name: /etc/docker/daemon.json - template: jinja @@ -89,10 +54,9 @@ docker_running: - enable: True - watch: - file: docker_daemon - - x509: trusttheca - require: - file: docker_daemon - - x509: trusttheca + - file: trusttheca # Reserve OS ports for Docker proxy in case boot settings are not already applied/present @@ -110,12 +74,12 @@ dockerreserveports: sos_docker_net: docker_network.present: - name: sobridge - - subnet: {{ DOCKER.range }} - - gateway: {{ DOCKER.gateway }} + - subnet: {{ DOCKERMERGED.range }} + - gateway: {{ DOCKERMERGED.gateway }} - options: com.docker.network.bridge.name: 'sobridge' com.docker.network.driver.mtu: '1500' com.docker.network.bridge.enable_ip_masquerade: 'true' com.docker.network.bridge.enable_icc: 'true' com.docker.network.bridge.host_binding_ipv4: '0.0.0.0' - - unless: 'docker network ls | grep sobridge' + - unless: ip l | grep sobridge diff --git a/salt/docker/soc_docker.yaml b/salt/docker/soc_docker.yaml index 3c4475236..e649700da 100644 --- a/salt/docker/soc_docker.yaml +++ b/salt/docker/soc_docker.yaml @@ -1,44 +1,82 @@ docker: gateway: description: Gateway for the default docker interface. - helpLink: docker.html + helpLink: docker advanced: True range: description: Default docker IP range for containers. - helpLink: docker.html + 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 + 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 containers: so-dockerregistry: &dockerOptions final_octet: description: Last octet of the container IP address. - helpLink: docker.html + helpLink: docker readonly: True advanced: True global: True port_bindings: description: List of port bindings for the container. - helpLink: docker.html + helpLink: docker advanced: True multiline: True forcedType: "[]string" custom_bind_mounts: description: List of custom local volume bindings. advanced: True - helpLink: docker.html + helpLink: docker multiline: True forcedType: "[]string" extra_hosts: description: List of additional host entries for the container. advanced: True - helpLink: docker.html + helpLink: docker multiline: True forcedType: "[]string" extra_env: description: List of additional ENV entries for the container. advanced: True - helpLink: docker.html + helpLink: docker multiline: True 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-elasticsearch: *dockerOptions so-influxdb: *dockerOptions @@ -62,43 +100,6 @@ docker: so-idh: *dockerOptions so-elastic-agent: *dockerOptions so-telegraf: *dockerOptions - so-steno: *dockerOptions - so-suricata: - final_octet: - description: Last octet of the container IP address. - helpLink: docker.html - readonly: True - advanced: True - global: True - port_bindings: - description: List of port bindings for the container. - helpLink: docker.html - advanced: True - multiline: True - forcedType: "[]string" - custom_bind_mounts: - description: List of custom local volume bindings. - advanced: True - helpLink: docker.html - multiline: True - forcedType: "[]string" - extra_hosts: - description: List of additional host entries for the container. - advanced: True - helpLink: docker.html - multiline: True - forcedType: "[]string" - extra_env: - description: List of additional ENV entries for the container. - advanced: True - helpLink: docker.html - multiline: True - forcedType: "[]string" - ulimits: - description: Ulimits for the container, in bytes. - advanced: True - helpLink: docker.html - multiline: True - forcedType: "[]string" + so-suricata: *dockerOptions so-zeek: *dockerOptions so-kafka: *dockerOptions diff --git a/salt/elastalert/enabled.sls b/salt/elastalert/enabled.sls index 6a1ff1440..d72c3b9c5 100644 --- a/salt/elastalert/enabled.sls +++ b/salt/elastalert/enabled.sls @@ -6,7 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: - elastalert.config @@ -24,7 +24,7 @@ so-elastalert: - user: so-elastalert - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastalert'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-elastalert'].ip }} - detach: True - binds: - /opt/so/rules/elastalert:/opt/elastalert/rules/:ro @@ -33,24 +33,30 @@ so-elastalert: - /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 - {% if DOCKER.containers['so-elastalert'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-elastalert'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-elastalert'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-elastalert'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - extra_hosts: - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {% if DOCKER.containers['so-elastalert'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-elastalert'].extra_hosts %} + {% if DOCKERMERGED.containers['so-elastalert'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-elastalert'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-elastalert'].extra_env %} + {% if DOCKERMERGED.containers['so-elastalert'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-elastalert'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-elastalert'].extra_env %} - {{ XTRAENV }} {% endfor %} {% 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: - cmd: wait_for_elasticsearch - file: elastarules @@ -60,7 +66,7 @@ so-elastalert: - watch: - file: elastaconf - onlyif: - - "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 8" {# only run this state if elasticsearch is version 8 #} + - "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 9" {# only run this state if elasticsearch is version 9 #} delete_so-elastalert_so-status.disabled: file.uncomment: diff --git a/salt/elasticfleet/files/certs/placeholder b/salt/elastalert/files/custom/.gitkeep similarity index 100% rename from salt/elasticfleet/files/certs/placeholder rename to salt/elastalert/files/custom/.gitkeep diff --git a/salt/elastalert/files/custom/placeholder b/salt/elastalert/files/custom/placeholder deleted file mode 100644 index 42e4ae4f0..000000000 --- a/salt/elastalert/files/custom/placeholder +++ /dev/null @@ -1 +0,0 @@ -THIS IS A PLACEHOLDER FILE \ No newline at end of file diff --git a/salt/elastalert/soc_elastalert.yaml b/salt/elastalert/soc_elastalert.yaml index 764ec87fc..123ead697 100644 --- a/salt/elastalert/soc_elastalert.yaml +++ b/salt/elastalert/soc_elastalert.yaml @@ -1,47 +1,48 @@ elastalert: enabled: description: Enables or disables the ElastAlert 2 process. This process is critical for ensuring alerts arrive in SOC, and for outbound notification delivery. - helpLink: elastalert.html + forcedType: bool + 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.html + 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.html + 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.html + 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.html + 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.html + 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.html + helpLink: elastalert forcedType: string files: custom: @@ -49,91 +50,131 @@ elastalert: 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.html + 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.html + 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.html + 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.html + 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.html + 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.html + 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.html + 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.html + 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.html + 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.html + helpLink: elastalert config: + scan_subdirectories: + description: Recursively scan subdirectories for rules. + forcedType: bool + advanced: True + global: True + helpLink: elastalert disable_rules_on_error: description: Disable rules on failure. + forcedType: bool global: True - helpLink: elastalert.html + helpLink: elastalert run_every: minutes: description: Amount of time in minutes between searches. global: True - helpLink: elastalert.html + helpLink: elastalert buffer_time: minutes: description: Amount of time in minutes to look through. global: True - helpLink: elastalert.html + helpLink: elastalert old_query_limit: minutes: description: Amount of time in minutes between queries to start at the most recently run query. global: True - helpLink: elastalert.html + helpLink: elastalert es_conn_timeout: description: Timeout in seconds for connecting to and reading from Elasticsearch. global: True - helpLink: elastalert.html + helpLink: elastalert max_query_size: description: The maximum number of documents that will be returned from Elasticsearch in a single query. global: True - helpLink: elastalert.html + helpLink: elastalert + 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: days: description: The retry window for failed alerts. global: True - helpLink: elastalert.html + helpLink: elastalert index_settings: shards: description: The number of shards for elastalert indices. global: True - helpLink: elastalert.html + helpLink: elastalert replicas: description: The number of replicas for elastalert indices. global: True - helpLink: elastalert.html + helpLink: elastalert + 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 diff --git a/salt/elastic-fleet-package-registry/enabled.sls b/salt/elastic-fleet-package-registry/enabled.sls index 3cd90ba87..e2833f5be 100644 --- a/salt/elastic-fleet-package-registry/enabled.sls +++ b/salt/elastic-fleet-package-registry/enabled.sls @@ -6,7 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: - elastic-fleet-package-registry.config @@ -21,30 +21,36 @@ so-elastic-fleet-package-registry: - user: 948 - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastic-fleet-package-registry'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-elastic-fleet-package-registry'].ip }} - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-elastic-fleet-package-registry'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-elastic-fleet-package-registry'].extra_hosts %} + {% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-elastic-fleet-package-registry'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} - binds: - {% for BIND in DOCKER.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-elastic-fleet-package-registry'].extra_env %} + {% if DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-elastic-fleet-package-registry'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-elastic-fleet-package-registry'].extra_env %} - {{ XTRAENV }} {% endfor %} {% 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: file.uncomment: - name: /opt/so/conf/so-status/so-status.conf diff --git a/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml b/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml index 3d8a2112b..fff1a51c0 100644 --- a/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml +++ b/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml @@ -1,4 +1,5 @@ elastic_fleet_package_registry: enabled: description: Enables or disables the Fleet package registry process. This process must remain enabled to allow Elastic Agent packages to be updated. + forcedType: bool advanced: True diff --git a/salt/elasticagent/enabled.sls b/salt/elasticagent/enabled.sls index 3c20c916f..c366ebbf7 100644 --- a/salt/elasticagent/enabled.sls +++ b/salt/elasticagent/enabled.sls @@ -6,9 +6,10 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - ca - elasticagent.config - elasticagent.sostatus @@ -21,17 +22,17 @@ so-elastic-agent: - user: 949 - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastic-agent'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-elastic-agent'].ip }} - extra_hosts: - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-elastic-agent'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-elastic-agent'].extra_hosts %} + {% if DOCKERMERGED.containers['so-elastic-agent'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-elastic-agent'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-elastic-agent'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-elastic-agent'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -40,23 +41,31 @@ so-elastic-agent: - /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro - /nsm:/nsm:ro - /opt/so/log:/opt/so/log:ro - {% if DOCKER.containers['so-elastic-agent'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-elastic-agent'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-elastic-agent'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-elastic-agent'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - environment: - FLEET_CA=/etc/pki/tls/certs/intca.crt - LOGS_PATH=logs - {% if DOCKER.containers['so-elastic-agent'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-elastic-agent'].extra_env %} + {% if DOCKERMERGED.containers['so-elastic-agent'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-elastic-agent'].extra_env %} - {{ XTRAENV }} {% endfor %} {% 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: - file: create-elastic-agent-config + - file: trusttheca - watch: - file: create-elastic-agent-config + - file: trusttheca delete_so-elastic-agent_so-status.disabled: file.uncomment: diff --git a/salt/elasticagent/files/elastic-agent.yml.jinja b/salt/elasticagent/files/elastic-agent.yml.jinja index 7d0b93344..283bf9508 100644 --- a/salt/elasticagent/files/elastic-agent.yml.jinja +++ b/salt/elasticagent/files/elastic-agent.yml.jinja @@ -3,7 +3,7 @@ {%- set ES_PASS = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') %} id: aea1ba80-1065-11ee-a369-97538913b6a9 -revision: 1 +revision: 4 outputs: default: type: elasticsearch @@ -22,242 +22,133 @@ agent: metrics: false features: {} inputs: - - id: logfile-logs-fefef78c-422f-4cfa-8abf-4cd1b9428f62 - name: import-evtx-logs - revision: 2 - type: logfile - use_output: default - meta: - package: - name: log - version: - data_stream: - namespace: so - package_policy_id: fefef78c-422f-4cfa-8abf-4cd1b9428f62 - streams: - - id: logfile-log.log-fefef78c-422f-4cfa-8abf-4cd1b9428f62 - data_stream: - dataset: import - paths: - - /nsm/import/*/evtx/*.json - processors: - - dissect: - field: log.file.path - tokenizer: '/nsm/import/%{import.id}/evtx/%{import.file}' - target_prefix: '' - - decode_json_fields: - fields: - - message - 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 + - id: filestream-filestream-85820eb0-25ef-11f0-a18d-1b26f69b8310 name: import-suricata-logs - revision: 2 - type: logfile + revision: 3 + type: filestream use_output: default meta: package: - name: log + name: filestream version: data_stream: namespace: so - package_policy_id: 3b56803d-5ade-4c93-b25e-9b37182f66b8 + package_policy_id: 85820eb0-25ef-11f0-a18d-1b26f69b8310 streams: - - id: logfile-log.log-3b56803d-5ade-4c93-b25e-9b37182f66b8 + - id: filestream-filestream.generic-85820eb0-25ef-11f0-a18d-1b26f69b8310 data_stream: dataset: import - pipeline: suricata.common paths: - /nsm/import/*/suricata/eve*.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 - category: network - target: event - dissect: + tokenizer: /nsm/import/%{import.id}/suricata/%{import.file} 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 + 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: log + name: filestream version: data_stream: namespace: so - package_policy_id: c327e1a3-1ebe-449c-a8eb-f6f35032e69d + package_policy_id: 86b4e960-25ef-11f0-a18d-1b26f69b8310 streams: - - id: logfile-log.log-c327e1a3-1ebe-449c-a8eb-f6f35032e69d + - id: filestream-filestream.generic-86b4e960-25ef-11f0-a18d-1b26f69b8310 data_stream: - dataset: soc - pipeline: common + dataset: import paths: - - /opt/so/log/soc/sensoroni-server.log + - /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: - - decode_json_fields: - add_error_key: true - process_array: true - max_depth: 2 - fields: - - message - target: soc + - dissect: + tokenizer: /nsm/import/%{import.id}/zeek/logs/%{import.file} + field: log.file.path + 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: - fields: - module: soc - dataset_temp: server - 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 + 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: 2 - type: logfile + revision: 3 + type: filestream use_output: default meta: package: - name: log + name: filestream version: data_stream: namespace: so - package_policy_id: 906e0d4c-9ec3-4c6a-bef6-e347ec9fd073 + package_policy_id: 91741240-25ef-11f0-a18d-1b26f69b8310 streams: - - id: logfile-log.log-906e0d4c-9ec3-4c6a-bef6-e347ec9fd073 + - id: filestream-filestream.generic-91741240-25ef-11f0-a18d-1b26f69b8310 data_stream: dataset: soc - pipeline: common 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: - add_error_key: true - process_array: true - max_depth: 2 fields: - message target: sensoroni + process_array: true + max_depth: 2 + add_error_key: true - add_fields: + target: event fields: + category: host module: soc dataset_temp: sensoroni - category: host - target: event - rename: - ignore_missing: true fields: - from: sensoroni.fields.sourceIp to: source.ip @@ -271,141 +162,100 @@ inputs: to: event.action - from: sensoroni.level to: log.level - - id: logfile-logs-df0d7f2c-221f-433b-b18b-d1cf83250515 - name: soc-salt-relay-logs - revision: 2 - type: logfile - use_output: default - meta: - package: - name: log - version: - data_stream: - namespace: so - package_policy_id: df0d7f2c-221f-433b-b18b-d1cf83250515 - streams: - - 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 + ignore_missing: true + file_identity.native: null + prospector.scanner.fingerprint.enabled: false + - id: filestream-filestream-976e3900-25ef-11f0-a18d-1b26f69b8310 name: suricata-logs - revision: 2 - type: logfile + revision: 3 + type: filestream use_output: default meta: package: - name: log + name: filestream version: data_stream: namespace: so - package_policy_id: d151d9bf-ff2a-4529-9520-c99244bc0253 + package_policy_id: 976e3900-25ef-11f0-a18d-1b26f69b8310 streams: - - id: logfile-log.log-d151d9bf-ff2a-4529-9520-c99244bc0253 + - id: filestream-filestream.generic-976e3900-25ef-11f0-a18d-1b26f69b8310 data_stream: dataset: suricata - pipeline: suricata.common paths: - /nsm/suricata/eve*.json + pipeline: suricata.common + prospector.scanner.recursive_glob: true + prospector.scanner.exclude_files: + - \.gz$ + clean_inactive: -1 + parsers: null processors: - add_fields: - fields: - module: suricata - category: network target: event - - id: logfile-logs-31f94d05-ae75-40ee-b9c5-0e0356eff327 + fields: + category: network + module: suricata + file_identity.native: null + prospector.scanner.fingerprint.enabled: false + - id: filestream-filestream-95091fe0-25ef-11f0-a18d-1b26f69b8310 name: strelka-logs - revision: 2 - type: logfile + revision: 3 + type: filestream use_output: default meta: package: - name: log + name: filestream version: data_stream: namespace: so - package_policy_id: 31f94d05-ae75-40ee-b9c5-0e0356eff327 + package_policy_id: 95091fe0-25ef-11f0-a18d-1b26f69b8310 streams: - - id: logfile-log.log-31f94d05-ae75-40ee-b9c5-0e0356eff327 + - id: filestream-filestream.generic-95091fe0-25ef-11f0-a18d-1b26f69b8310 data_stream: dataset: strelka - pipeline: strelka.file paths: - /nsm/strelka/log/strelka.log + pipeline: strelka.file + prospector.scanner.recursive_glob: true + prospector.scanner.exclude_files: + - \.gz$ + clean_inactive: -1 + parsers: null processors: - add_fields: - fields: - module: strelka - category: file target: event - - id: logfile-logs-6197fe84-9b58-4d9b-8464-3d517f28808d + fields: + category: file + module: strelka + file_identity.native: null + prospector.scanner.fingerprint.enabled: false + - id: filestream-filestream-9f309ca0-25ef-11f0-a18d-1b26f69b8310 name: zeek-logs - revision: 1 - type: logfile + revision: 2 + type: filestream use_output: default meta: package: - name: log - version: + name: filestream + version: data_stream: namespace: so - package_policy_id: 6197fe84-9b58-4d9b-8464-3d517f28808d + package_policy_id: 9f309ca0-25ef-11f0-a18d-1b26f69b8310 streams: - - id: logfile-log.log-6197fe84-9b58-4d9b-8464-3d517f28808d + - id: filestream-filestream.generic-9f309ca0-25ef-11f0-a18d-1b26f69b8310 data_stream: dataset: zeek paths: - /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: - dissect: - tokenizer: '/nsm/zeek/logs/current/%{pipeline}.log' + tokenizer: /nsm/zeek/logs/current/%{pipeline}.log field: log.file.path trim_chars: .log target_prefix: '' @@ -427,18 +277,17 @@ inputs: regexp: pipeline: >- ^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm* - exclude_files: - - >- - broker|capture_loss|cluster|ecat_arp_info|known_hosts|known_services|loaded_scripts|ntp|ocsp|packet_filter|reporter|stats|stderr|stdout.log$ + file_identity.native: null + prospector.scanner.fingerprint.enabled: false - id: udp-udp-35051de0-46a5-11ee-8d5d-9f98c8182f60 name: syslog-udp-514 - revision: 3 + revision: 4 type: udp use_output: default meta: package: name: udp - version: 1.10.0 + version: data_stream: namespace: so package_policy_id: 35051de0-46a5-11ee-8d5d-9f98c8182f60 @@ -458,13 +307,13 @@ inputs: - syslog - id: tcp-tcp-33d37bb0-46a5-11ee-8d5d-9f98c8182f60 name: syslog-tcp-514 - revision: 3 + revision: 4 type: tcp use_output: default meta: package: name: tcp - version: 1.10.0 + version: data_stream: namespace: so package_policy_id: 33d37bb0-46a5-11ee-8d5d-9f98c8182f60 diff --git a/salt/elasticagent/soc_elasticagent.yaml b/salt/elasticagent/soc_elasticagent.yaml index a24ac1985..c78d46c6c 100644 --- a/salt/elasticagent/soc_elasticagent.yaml +++ b/salt/elasticagent/soc_elasticagent.yaml @@ -1,4 +1,5 @@ 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 diff --git a/salt/elasticfleet/config.sls b/salt/elasticfleet/config.sls index 3bdd495c1..9c79dfab6 100644 --- a/salt/elasticfleet/config.sls +++ b/salt/elasticfleet/config.sls @@ -11,6 +11,7 @@ include: - elasticfleet.artifact_registry + - elasticfleet.ssl # Add EA Group elasticfleetgroup: @@ -95,6 +96,9 @@ soresourcesrepoclone: - rev: 'main' - depth: 1 - force_reset: True + - retry: + attempts: 3 + interval: 10 {% endif %} elasticdefendconfdir: diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls index db10a7182..89ba1f80a 100644 --- a/salt/elasticfleet/enabled.sls +++ b/salt/elasticfleet/enabled.sls @@ -6,16 +6,17 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} {# This value is generated during node install and stored in minion pillar #} {% set SERVICETOKEN = salt['pillar.get']('elasticfleet:config:server:es_token','') %} include: + - ca + - logstash.ssl - elasticfleet.config - elasticfleet.sostatus - - ssl {% if grains.role not in ['so-fleet'] %} # Wait for Elasticsearch to be ready - no reason to try running Elastic Fleet server if ES is not ready @@ -93,17 +94,17 @@ so-elastic-fleet: - user: 947 - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastic-fleet'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-elastic-fleet'].ip }} - extra_hosts: - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-elastic-fleet'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-elastic-fleet'].extra_hosts %} + {% if DOCKERMERGED.containers['so-elastic-fleet'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-elastic-fleet'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-elastic-fleet'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-elastic-fleet'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -111,8 +112,8 @@ so-elastic-fleet: - /etc/pki/elasticfleet-server.key:/etc/pki/elasticfleet-server.key:ro - /etc/pki/tls/certs/intca.crt:/etc/pki/tls/certs/intca.crt:ro - /opt/so/log/elasticfleet:/usr/share/elastic-agent/logs - {% if DOCKER.containers['so-elastic-fleet'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-elastic-fleet'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-elastic-fleet'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-elastic-fleet'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} @@ -127,12 +128,23 @@ so-elastic-fleet: - FLEET_CA=/etc/pki/tls/certs/intca.crt - FLEET_SERVER_ELASTICSEARCH_CA=/etc/pki/tls/certs/intca.crt - LOGS_PATH=logs - {% if DOCKER.containers['so-elastic-fleet'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-elastic-fleet'].extra_env %} + {% if DOCKERMERGED.containers['so-elastic-fleet'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-elastic-fleet'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-elastic-fleet'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-elastic-fleet'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: + - file: trusttheca + - x509: etc_elasticfleet_key + - x509: etc_elasticfleet_crt + - require: + - file: trusttheca - x509: etc_elasticfleet_key - x509: etc_elasticfleet_crt {% endif %} diff --git a/salt/suricata/rules/PLACEHOLDER b/salt/elasticfleet/files/certs/.gitkeep similarity index 100% rename from salt/suricata/rules/PLACEHOLDER rename to salt/elasticfleet/files/certs/.gitkeep diff --git a/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/import-zeek-logs.json b/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/import-zeek-logs.json index 492db03dc..ac03f3c1d 100644 --- a/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/import-zeek-logs.json +++ b/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/import-zeek-logs.json @@ -2,7 +2,7 @@ {%- raw -%} { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "import-zeek-logs", @@ -10,19 +10,31 @@ "description": "Zeek Import logs", "policy_id": "so-grid-nodes_general", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/import/*/zeek/logs/*.log" ], "data_stream.dataset": "import", - "tags": [], + "pipeline": "", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": ["({%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%})(\\..+)?\\.log$"], + "include_files": [], "processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/zeek/logs/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- script:\n lang: javascript\n source: >\n function process(event) {\n var pl = event.Get(\"import.file\").slice(0,-4);\n event.Put(\"@metadata.pipeline\", \"zeek.\" + pl);\n }\n- add_fields:\n target: event\n fields:\n category: network\n module: zeek\n imported: true\n- add_tags:\n tags: \"ics\"\n when:\n regexp:\n import.file: \"^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*\"", - "custom": "exclude_files: [\"{%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%}.log$\"]\n" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } diff --git a/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/kratos-logs.json b/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/kratos-logs.json index f6b01cdff..545588521 100644 --- a/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/kratos-logs.json +++ b/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/kratos-logs.json @@ -11,36 +11,51 @@ {%- endif -%} { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "kratos-logs", - "namespace": "so", "description": "Kratos logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/kratos/kratos.log" ], "data_stream.dataset": "kratos", - "tags": ["so-kratos"], + "pipeline": "kratos", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], {%- if valid_identities -%} "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- add_fields:\n target: event\n fields:\n category: iam\n module: kratos\n- if:\n has_fields:\n - identity_id\n then:{% for id, email in identities %}\n - if:\n equals:\n identity_id: \"{{ id }}\"\n then:\n - add_fields:\n target: ''\n fields:\n user.name: \"{{ email }}\"{% endfor %}", {%- else -%} "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- add_fields:\n target: event\n fields:\n category: iam\n module: kratos", {%- endif -%} - "custom": "pipeline: kratos" + "tags": [ + "so-kratos" + ], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} - +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/zeek-logs.json b/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/zeek-logs.json index 5462dc861..4af2b2921 100644 --- a/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/zeek-logs.json +++ b/salt/elasticfleet/files/integrations-dynamic/grid-nodes_general/zeek-logs.json @@ -2,28 +2,38 @@ {%- raw -%} { "package": { - "name": "log", + "name": "filestream", "version": "" }, - "id": "zeek-logs", "name": "zeek-logs", "namespace": "so", "description": "Zeek logs", "policy_id": "so-grid-nodes_general", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/zeek/logs/current/*.log" ], "data_stream.dataset": "zeek", - "tags": [], + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": ["({%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%})(\\..+)?\\.log$"], + "include_files": [], "processors": "- dissect:\n tokenizer: \"/nsm/zeek/logs/current/%{pipeline}.log\"\n field: \"log.file.path\"\n trim_chars: \".log\"\n target_prefix: \"\"\n- script:\n lang: javascript\n source: >\n function process(event) {\n var pl = event.Get(\"pipeline\");\n event.Put(\"@metadata.pipeline\", \"zeek.\" + pl);\n }\n- add_fields:\n target: event\n fields:\n category: network\n module: zeek\n- add_tags:\n tags: \"ics\"\n when:\n regexp:\n pipeline: \"^bacnet*|^bsap*|^cip*|^cotp*|^dnp3*|^ecat*|^enip*|^modbus*|^opcua*|^profinet*|^s7comm*\"", - "custom": "exclude_files: [\"{%- endraw -%}{{ ELASTICFLEETMERGED.logging.zeek.excluded | join('|') }}{%- raw -%}.log$\"]\n" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } @@ -31,4 +41,4 @@ }, "force": true } -{%- endraw -%} +{%- endraw -%} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json index fb9069e83..debfc73a3 100644 --- a/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json +++ b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json @@ -5,7 +5,7 @@ "package": { "name": "endpoint", "title": "Elastic Defend", - "version": "8.18.1", + "version": "9.0.2", "requires_root": true }, "enabled": true, diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json index f1b1dace9..a4f944ba5 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json @@ -1,26 +1,43 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "hydra-logs", - "namespace": "so", "description": "Hydra logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/hydra/hydra.log" ], "data_stream.dataset": "hydra", - "tags": ["so-hydra"], - "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: iam\n module: hydra", - "custom": "pipeline: hydra" + "pipeline": "hydra", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], + "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- add_fields:\n target: event\n fields:\n category: iam\n module: hydra", + "tags": [ + "so-hydra" + ], + "recursive_glob": true, + "ignore_older": "72h", + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } @@ -28,3 +45,5 @@ }, "force": true } + + diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json index 9f66c1937..fef9c57fb 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/idh-logs.json @@ -1,30 +1,44 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "idh-logs", - "namespace": "so", "description": "IDH integration", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/idh/opencanary.log" ], "data_stream.dataset": "idh", - "tags": [], + "pipeline": "common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n add_error_key: true\n- convert:\n fields:\n - {from: \"logtype\", to: \"event.code\", type: \"string\"}\n- drop_fields:\n when:\n equals:\n event.code: \"1001\"\n fields: [\"src_host\", \"src_port\", \"dst_host\", \"dst_port\" ]\n ignore_missing: true\n- rename:\n fields:\n - from: \"src_host\"\n to: \"source.ip\"\n - from: \"src_port\"\n to: \"source.port\"\n - from: \"dst_host\"\n to: \"destination.host\"\n - from: \"dst_port\"\n to: \"destination.port\"\n ignore_missing: true\n- drop_fields:\n fields: '[\"prospector\", \"input\", \"offset\", \"beat\"]'\n- add_fields:\n target: event\n fields:\n category: host\n module: opencanary", - "custom": "pipeline: common" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json index dd95e6337..50ffd5dc7 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/import-evtx-logs.json @@ -1,33 +1,46 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "import-evtx-logs", - "namespace": "so", "description": "Import Windows EVTX logs", "policy_id": "so-grid-nodes_general", - "vars": {}, + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/import/*/evtx/*.json" ], "data_stream.dataset": "import", - "custom": "", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- dissect:\n tokenizer: \"/nsm/import/%{import.id}/evtx/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n- decode_json_fields:\n fields: [\"message\"]\n target: \"\"\n- drop_fields:\n fields: [\"host\"]\n ignore_missing: true\n- add_fields:\n target: data_stream\n fields:\n type: logs\n dataset: system.security\n- add_fields:\n target: event\n fields:\n dataset: system.security\n module: system\n imported: true\n- add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.security-2.6.1\n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-Sysmon/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.sysmon_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.sysmon_operational\n module: windows\n imported: true\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.sysmon_operational-3.1.2\n- if:\n equals:\n winlog.channel: 'Application'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.application\n - add_fields:\n target: event\n fields:\n dataset: system.application\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.application-2.6.1\n- if:\n equals:\n winlog.channel: 'System'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: system.system\n - add_fields:\n target: event\n fields:\n dataset: system.system\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-system.system-2.6.1\n \n- if:\n equals:\n winlog.channel: 'Microsoft-Windows-PowerShell/Operational'\n then: \n - add_fields:\n target: data_stream\n fields:\n dataset: windows.powershell_operational\n - add_fields:\n target: event\n fields:\n dataset: windows.powershell_operational\n module: windows\n - add_fields:\n target: \"@metadata\"\n fields:\n pipeline: logs-windows.powershell_operational-3.1.2\n- add_fields:\n target: data_stream\n fields:\n dataset: import", "tags": [ "import" - ] + ], + "recursive_glob": true, + "ignore_older": "72h", + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/import-suricata-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/import-suricata-logs.json index c9b036e36..b8f3b0b29 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/import-suricata-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/import-suricata-logs.json @@ -1,30 +1,45 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "import-suricata-logs", - "namespace": "so", "description": "Import Suricata logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/import/*/suricata/eve*.json" ], "data_stream.dataset": "import", + "pipeline": "suricata.common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], + "processors": "- add_fields:\n target: event\n fields:\n category: network\n module: suricata\n imported: true\n- dissect:\n tokenizer: \"/nsm/import/%{import.id}/suricata/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"\n", "tags": [], - "processors": "- add_fields:\n target: event\n fields:\n category: network\n module: suricata\n imported: true\n- dissect:\n tokenizer: \"/nsm/import/%{import.id}/suricata/%{import.file}\"\n field: \"log.file.path\"\n target_prefix: \"\"", - "custom": "pipeline: suricata.common" + "recursive_glob": true, + "ignore_older": "72h", + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/redis-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/redis-logs.json index b822421eb..2d16039bb 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/redis-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/redis-logs.json @@ -15,7 +15,7 @@ "enabled": true, "vars": { "paths": [ - "/opt/so/log/redis/redis.log" + "/opt/so/log/redis/redis-server.log" ], "tags": [ "redis-log" diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/rita-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/rita-logs.json index a97faaa5f..70259c3cf 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/rita-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/rita-logs.json @@ -1,18 +1,17 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "rita-logs", - "namespace": "so", "description": "RITA Logs", "policy_id": "so-grid-nodes_general", - "vars": {}, + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ @@ -20,15 +19,28 @@ "/nsm/rita/exploded-dns.csv", "/nsm/rita/long-connections.csv" ], - "exclude_files": [], - "ignore_older": "72h", "data_stream.dataset": "rita", - "tags": [], + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- dissect:\n tokenizer: \"/nsm/rita/%{pipeline}.csv\"\n field: \"log.file.path\"\n trim_chars: \".csv\"\n target_prefix: \"\"\n- script:\n lang: javascript\n source: >\n function process(event) {\n var pl = event.Get(\"pipeline\").split(\"-\");\n if (pl.length > 1) {\n pl = pl[1];\n }\n else {\n pl = pl[0];\n }\n event.Put(\"@metadata.pipeline\", \"rita.\" + pl);\n }\n- add_fields:\n target: event\n fields:\n category: network\n module: rita", - "custom": "exclude_lines: ['^Score', '^Source', '^Domain', '^No results']" + "tags": [], + "recursive_glob": true, + "ignore_older": "72h", + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } - } + }, + "force": true } diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/so-ip-mappings.json b/salt/elasticfleet/files/integrations/grid-nodes_general/so-ip-mappings.json index fdcd36815..a14e63559 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/so-ip-mappings.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/so-ip-mappings.json @@ -1,29 +1,41 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "so-ip-mappings", - "namespace": "so", "description": "IP Description mappings", "policy_id": "so-grid-nodes_general", - "vars": {}, + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/custom-mappings/ip-descriptions.csv" ], "data_stream.dataset": "hostnamemappings", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], + "processors": "- decode_csv_fields:\n fields:\n message: decoded.csv\n separator: \",\"\n ignore_missing: false\n overwrite_keys: true\n trim_leading_space: true\n fail_on_error: true\n\n- extract_array:\n field: decoded.csv\n mappings:\n so.ip_address: '0'\n so.description: '1'\n\n- script:\n lang: javascript\n source: >\n function process(event) {\n var ip = event.Get('so.ip_address');\n var validIpRegex = /^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/\n if (!validIpRegex.test(ip)) {\n event.Cancel();\n }\n }\n- fingerprint:\n fields: [\"so.ip_address\"]\n target_field: \"@metadata._id\"\n", "tags": [ "so-ip-mappings" ], - "processors": "- decode_csv_fields:\n fields:\n message: decoded.csv\n separator: \",\"\n ignore_missing: false\n overwrite_keys: true\n trim_leading_space: true\n fail_on_error: true\n\n- extract_array:\n field: decoded.csv\n mappings:\n so.ip_address: '0'\n so.description: '1'\n\n- script:\n lang: javascript\n source: >\n function process(event) {\n var ip = event.Get('so.ip_address');\n var validIpRegex = /^((25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]?\\d)$/\n if (!validIpRegex.test(ip)) {\n event.Cancel();\n }\n }\n- fingerprint:\n fields: [\"so.ip_address\"]\n target_field: \"@metadata._id\"\n", - "custom": "" + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } @@ -31,5 +43,3 @@ }, "force": true } - - diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-auth-sync-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-auth-sync-logs.json index aa39c177b..f4fd38e9d 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-auth-sync-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-auth-sync-logs.json @@ -1,30 +1,44 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "soc-auth-sync-logs", - "namespace": "so", "description": "Security Onion - Elastic Auth Sync - Logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/soc/sync.log" ], "data_stream.dataset": "soc", - "tags": ["so-soc"], + "pipeline": "common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- dissect:\n tokenizer: \"%{event.action}\"\n field: \"message\"\n target_prefix: \"\"\n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: auth_sync", - "custom": "pipeline: common" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-detections-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-detections-logs.json index 5649b481d..f1bdbc922 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-detections-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-detections-logs.json @@ -1,35 +1,48 @@ { - "policy_id": "so-grid-nodes_general", "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "soc-detections-logs", "description": "Security Onion Console - Detections Logs", + "policy_id": "so-grid-nodes_general", "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/soc/detections_runtime-status_sigma.log", "/opt/so/log/soc/detections_runtime-status_yara.log" ], - "exclude_files": [], - "ignore_older": "72h", "data_stream.dataset": "soc", + "pipeline": "common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], + "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"soc\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: detections\n- rename:\n fields:\n - from: \"soc.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"soc.fields.status\"\n to: \"http.response.status_code\"\n - from: \"soc.fields.method\"\n to: \"http.request.method\"\n - from: \"soc.fields.path\"\n to: \"url.path\"\n - from: \"soc.message\"\n to: \"event.action\"\n - from: \"soc.level\"\n to: \"log.level\"\n ignore_missing: true", "tags": [ "so-soc" ], - "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"soc\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: detections\n- rename:\n fields:\n - from: \"soc.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"soc.fields.status\"\n to: \"http.response.status_code\"\n - from: \"soc.fields.method\"\n to: \"http.request.method\"\n - from: \"soc.fields.path\"\n to: \"url.path\"\n - from: \"soc.message\"\n to: \"event.action\"\n - from: \"soc.level\"\n to: \"log.level\"\n ignore_missing: true", - "custom": "pipeline: common" + "recursive_glob": true, + "ignore_older": "72h", + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-salt-relay-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-salt-relay-logs.json index cc92092e9..cb08d5b12 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-salt-relay-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-salt-relay-logs.json @@ -1,30 +1,46 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "soc-salt-relay-logs", - "namespace": "so", "description": "Security Onion - Salt Relay - Logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/soc/salt-relay.log" ], "data_stream.dataset": "soc", - "tags": ["so-soc"], + "pipeline": "common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- dissect:\n tokenizer: \"%{soc.ts} | %{event.action}\"\n field: \"message\"\n target_prefix: \"\"\n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: salt_relay", - "custom": "pipeline: common" + "tags": [ + "so-soc" + ], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-sensoroni-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-sensoroni-logs.json index 61ad057f4..11e686c3d 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-sensoroni-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-sensoroni-logs.json @@ -1,30 +1,44 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "soc-sensoroni-logs", - "namespace": "so", "description": "Security Onion - Sensoroni - Logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/sensoroni/sensoroni.log" ], "data_stream.dataset": "soc", - "tags": [], + "pipeline": "common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"sensoroni\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: sensoroni\n- rename:\n fields:\n - from: \"sensoroni.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"sensoroni.fields.status\"\n to: \"http.response.status_code\"\n - from: \"sensoroni.fields.method\"\n to: \"http.request.method\"\n - from: \"sensoroni.fields.path\"\n to: \"url.path\"\n - from: \"sensoroni.message\"\n to: \"event.action\"\n - from: \"sensoroni.level\"\n to: \"log.level\"\n ignore_missing: true", - "custom": "pipeline: common" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, - "force": true -} +"force": true +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-server-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-server-logs.json index a875e4bfc..decb6b22a 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/soc-server-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/soc-server-logs.json @@ -1,30 +1,46 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "soc-server-logs", - "namespace": "so", "description": "Security Onion Console Logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/opt/so/log/soc/sensoroni-server.log" ], "data_stream.dataset": "soc", - "tags": ["so-soc"], + "pipeline": "common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- decode_json_fields:\n fields: [\"message\"]\n target: \"soc\"\n process_array: true\n max_depth: 2\n add_error_key: true \n- add_fields:\n target: event\n fields:\n category: host\n module: soc\n dataset_temp: server\n- rename:\n fields:\n - from: \"soc.fields.sourceIp\"\n to: \"source.ip\"\n - from: \"soc.fields.status\"\n to: \"http.response.status_code\"\n - from: \"soc.fields.method\"\n to: \"http.request.method\"\n - from: \"soc.fields.path\"\n to: \"url.path\"\n - from: \"soc.message\"\n to: \"event.action\"\n - from: \"soc.level\"\n to: \"log.level\"\n ignore_missing: true", - "custom": "pipeline: common" + "tags": [ + "so-soc" + ], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/strelka-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/strelka-logs.json index 89e9bbe8e..1f0203a91 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/strelka-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/strelka-logs.json @@ -1,30 +1,44 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "strelka-logs", - "namespace": "so", - "description": "Strelka logs", + "description": "Strelka Logs", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/strelka/log/strelka.log" ], "data_stream.dataset": "strelka", - "tags": [], + "pipeline": "strelka.file", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- add_fields:\n target: event\n fields:\n category: file\n module: strelka", - "custom": "pipeline: strelka.file" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } } }, "force": true -} +} \ No newline at end of file diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/suricata-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/suricata-logs.json index c3b04fd86..26dae5225 100644 --- a/salt/elasticfleet/files/integrations/grid-nodes_general/suricata-logs.json +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/suricata-logs.json @@ -1,26 +1,40 @@ { "package": { - "name": "log", + "name": "filestream", "version": "" }, "name": "suricata-logs", - "namespace": "so", "description": "Suricata integration", "policy_id": "so-grid-nodes_general", + "namespace": "so", "inputs": { - "logs-logfile": { + "filestream-filestream": { "enabled": true, "streams": { - "log.logs": { + "filestream.generic": { "enabled": true, "vars": { "paths": [ "/nsm/suricata/eve*.json" ], "data_stream.dataset": "suricata", - "tags": [], + "pipeline": "suricata.common", + "parsers": "#- ndjson:\n# target: \"\"\n# message_key: msg\n#- multiline:\n# type: count\n# count_lines: 3\n", + "exclude_files": [ + "\\.gz$" + ], + "include_files": [], "processors": "- add_fields:\n target: event\n fields:\n category: network\n module: suricata", - "custom": "pipeline: suricata.common" + "tags": [], + "recursive_glob": true, + "clean_inactive": -1, + "harvester_limit": 0, + "fingerprint": false, + "fingerprint_offset": 0, + "fingerprint_length": "64", + "file_identity_native": true, + "exclude_lines": [], + "include_lines": [] } } } diff --git a/salt/elasticfleet/files/integrations/grid-nodes_heavy/elasticsearch-grid-nodes.json b/salt/elasticfleet/files/integrations/grid-nodes_heavy/elasticsearch-grid-nodes.json new file mode 100644 index 000000000..43c0c92b2 --- /dev/null +++ b/salt/elasticfleet/files/integrations/grid-nodes_heavy/elasticsearch-grid-nodes.json @@ -0,0 +1,107 @@ +{ + "package": { + "name": "elasticsearch", + "version": "" + }, + "name": "elasticsearch-grid-nodes_heavy", + "namespace": "default", + "description": "Elasticsearch Logs", + "policy_id": "so-grid-nodes_heavy", + "inputs": { + "elasticsearch-logfile": { + "enabled": true, + "streams": { + "elasticsearch.audit": { + "enabled": false, + "vars": { + "paths": [ + "/var/log/elasticsearch/*_audit.json" + ] + } + }, + "elasticsearch.deprecation": { + "enabled": false, + "vars": { + "paths": [ + "/var/log/elasticsearch/*_deprecation.json" + ] + } + }, + "elasticsearch.gc": { + "enabled": false, + "vars": { + "paths": [ + "/var/log/elasticsearch/gc.log.[0-9]*", + "/var/log/elasticsearch/gc.log" + ] + } + }, + "elasticsearch.server": { + "enabled": true, + "vars": { + "paths": [ + "/opt/so/log/elasticsearch/*.json" + ] + } + }, + "elasticsearch.slowlog": { + "enabled": false, + "vars": { + "paths": [ + "/var/log/elasticsearch/*_index_search_slowlog.json", + "/var/log/elasticsearch/*_index_indexing_slowlog.json" + ] + } + } + } + }, + "elasticsearch-elasticsearch/metrics": { + "enabled": false, + "vars": { + "hosts": [ + "http://localhost:9200" + ], + "scope": "node" + }, + "streams": { + "elasticsearch.stack_monitoring.ccr": { + "enabled": false + }, + "elasticsearch.stack_monitoring.cluster_stats": { + "enabled": false + }, + "elasticsearch.stack_monitoring.enrich": { + "enabled": false + }, + "elasticsearch.stack_monitoring.index": { + "enabled": false + }, + "elasticsearch.stack_monitoring.index_recovery": { + "enabled": false, + "vars": { + "active.only": true + } + }, + "elasticsearch.stack_monitoring.index_summary": { + "enabled": false + }, + "elasticsearch.stack_monitoring.ml_job": { + "enabled": false + }, + "elasticsearch.stack_monitoring.node": { + "enabled": false + }, + "elasticsearch.stack_monitoring.node_stats": { + "enabled": false + }, + "elasticsearch.stack_monitoring.pending_tasks": { + "enabled": false + }, + "elasticsearch.stack_monitoring.shard": { + "enabled": false + } + } + } + }, + "force": true +} diff --git a/salt/elasticfleet/install_agent_grid.sls b/salt/elasticfleet/install_agent_grid.sls index 4a185e0bb..482af2e1e 100644 --- a/salt/elasticfleet/install_agent_grid.sls +++ b/salt/elasticfleet/install_agent_grid.sls @@ -8,7 +8,9 @@ {% endif %} {% set AGENT_STATUS = salt['service.available']('elastic-agent') %} -{% if not AGENT_STATUS %} +{% set AGENT_EXISTS = salt['file.file_exists']('/opt/Elastic/Agent/elastic-agent') %} + +{% if not AGENT_STATUS or not AGENT_EXISTS %} pull_agent_installer: file.managed: @@ -19,7 +21,7 @@ pull_agent_installer: run_installer: cmd.run: - - name: ./so-elastic-agent_linux_amd64 -token={{ GRIDNODETOKEN }} + - name: ./so-elastic-agent_linux_amd64 -token={{ GRIDNODETOKEN }} -force - cwd: /opt/so - retry: attempts: 3 diff --git a/salt/elasticfleet/integration-defaults.map.jinja b/salt/elasticfleet/integration-defaults.map.jinja index 69ce7f3af..f85a95ec9 100644 --- a/salt/elasticfleet/integration-defaults.map.jinja +++ b/salt/elasticfleet/integration-defaults.map.jinja @@ -21,6 +21,7 @@ 'azure_application_insights.app_state': 'azure.app_state', 'azure_billing.billing': 'azure.billing', 'azure_functions.metrics': 'azure.function', + 'azure_ai_foundry.metrics': 'azure.ai_foundry', 'azure_metrics.compute_vm_scaleset': 'azure.compute_vm_scaleset', 'azure_metrics.compute_vm': 'azure.compute_vm', 'azure_metrics.container_instance': 'azure.container_instance', diff --git a/salt/elasticfleet/soc_elasticfleet.yaml b/salt/elasticfleet/soc_elasticfleet.yaml index d78189f96..710b7c1ff 100644 --- a/salt/elasticfleet/soc_elasticfleet.yaml +++ b/salt/elasticfleet/soc_elasticfleet.yaml @@ -1,14 +1,15 @@ elasticfleet: enabled: description: Enables or disables the Elastic Fleet process. This process is critical for managing Elastic Agents. + forcedType: bool advanced: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet enable_manager_output: description: Setting this option to False should only be considered if there is at least one receiver node in the grid. If True, Elastic Agent will send events to the manager and receivers. If False, events will only be send to the receivers. advanced: True global: True forcedType: bool - helpLink: elastic-fleet.html + helpLink: elastic-fleet files: soc: elastic-defend-disabled-filters__yaml: @@ -17,7 +18,7 @@ elasticfleet: syntax: yaml file: True global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True elastic-defend-custom-filters__yaml: title: Custom Elastic Defend filters @@ -25,31 +26,32 @@ elasticfleet: syntax: yaml file: True global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True logging: zeek: excluded: description: This is a list of Zeek logs that are excluded from being shipped through the data processing pipeline. If you remove a log from this list, Elastic Agent will attempt to process it. If an ingest node pipeline is not available to process the logs, you may experience errors. forcedType: "[]string" - helpLink: zeek.html + helpLink: zeek config: defend_filters: enable_auto_configuration: description: Enable auto-configuration and management of the Elastic Defend Exclusion filters. + forcedType: bool global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True subscription_integrations: description: Enable the installation of integrations that require an Elastic license. global: True forcedType: bool - helpLink: elastic-fleet.html + helpLink: elastic-fleet auto_upgrade_integrations: description: Enables or disables automatically upgrading Elastic Agent integrations. global: True forcedType: bool - helpLink: elastic-fleet.html + helpLink: elastic-fleet outputs: logstash: bulk_max_size: @@ -57,67 +59,68 @@ elasticfleet: global: True forcedType: int advanced: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet worker: description: The number of workers per configured host publishing events. global: True forcedType: int advanced: true - helpLink: elastic-fleet.html + helpLink: elastic-fleet queue_mem_events: title: queued events description: The number of events the queue can store. This value should be evenly divisible by the smaller of 'bulk_max_size' to avoid sending partial batches to the output. global: True forcedType: int advanced: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet timeout: description: The number of seconds to wait for responses from the Logstash server before timing out. Eg 30s regex: ^[0-9]+s$ advanced: True global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet loadbalance: description: If true and multiple Logstash hosts are configured, the output plugin load balances published events onto all Logstash hosts. If false, the output plugin sends all events to one host (determined at random) and switches to another host if the selected one becomes unresponsive. forcedType: bool advanced: True global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet compression_level: description: The gzip compression level. The compression level must be in the range of 1 (best speed) to 9 (best compression). regex: ^[1-9]$ forcedType: int advanced: True global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet server: custom_fqdn: description: Custom FQDN for Agents to connect to. One per line. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: "[]string" enable_auto_configuration: description: Enable auto-configuration of Logstash Outputs & Fleet Host URLs. + forcedType: bool global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True endpoints_enrollment: description: Endpoint enrollment key. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet sensitive: True advanced: True es_token: description: Elastic auth token. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet sensitive: True advanced: True grid_enrollment: description: Grid enrollment key. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet sensitive: True advanced: True optional_integrations: @@ -125,57 +128,57 @@ elasticfleet: enabled_nodes: description: Fleet nodes with the Sublime Platform integration enabled. Enter one per line. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: "[]string" api_key: description: API key for Sublime Platform. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: string sensitive: True base_url: description: Base URL for Sublime Platform. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: string poll_interval: description: Poll interval for alerts from Sublime Platform. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: string limit: description: The maximum number of message groups to return from Sublime Platform. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: int kismet: base_url: description: Base URL for Kismet. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: string poll_interval: description: Poll interval for wireless device data from Kismet. Integration is currently configured to return devices seen as active by any Kismet sensor within the last 10 minutes. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: string api_key: description: API key for Kismet. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: string sensitive: True enabled_nodes: description: Fleet nodes with the Kismet integration enabled. Enter one per line. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet advanced: True forcedType: "[]string" diff --git a/salt/elasticfleet/ssl.sls b/salt/elasticfleet/ssl.sls new file mode 100644 index 000000000..8d19ea68c --- /dev/null +++ b/salt/elasticfleet/ssl.sls @@ -0,0 +1,186 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} +{% from 'ca/map.jinja' import CA %} + +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %} + +{% if grains['role'] not in [ 'so-heavynode', 'so-receiver'] %} +# Start -- Elastic Fleet Host Cert +etc_elasticfleet_key: + x509.private_key_managed: + - name: /etc/pki/elasticfleet-server.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/elasticfleet-server.key') -%} + - prereq: + - x509: etc_elasticfleet_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +etc_elasticfleet_crt: + x509.certificate_managed: + - name: /etc/pki/elasticfleet-server.crt + - ca_server: {{ CA.server }} + - signing_policy: elasticfleet + - private_key: /etc/pki/elasticfleet-server.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }},DNS:{{ GLOBALS.url_base }},IP:{{ GLOBALS.node_ip }}{% if ELASTICFLEETMERGED.config.server.custom_fqdn | length > 0 %},DNS:{{ ELASTICFLEETMERGED.config.server.custom_fqdn | join(',DNS:') }}{% endif %} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + +efperms: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-server.key + - mode: 640 + - group: 939 + +chownelasticfleetcrt: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-server.crt + - mode: 640 + - user: 947 + - group: 939 + +chownelasticfleetkey: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-server.key + - mode: 640 + - user: 947 + - group: 939 +# End -- Elastic Fleet Host Cert +{% endif %} # endif is for not including HeavyNodes & Receivers + + +# Start -- Elastic Fleet Client Cert for Agent (Mutual Auth with Logstash Output) +etc_elasticfleet_agent_key: + x509.private_key_managed: + - name: /etc/pki/elasticfleet-agent.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/elasticfleet-agent.key') -%} + - prereq: + - x509: etc_elasticfleet_agent_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +etc_elasticfleet_agent_crt: + x509.certificate_managed: + - name: /etc/pki/elasticfleet-agent.crt + - ca_server: {{ CA.server }} + - signing_policy: elasticfleet + - private_key: /etc/pki/elasticfleet-agent.key + - CN: {{ GLOBALS.hostname }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + cmd.run: + - name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-agent.key -topk8 -out /etc/pki/elasticfleet-agent.p8 -nocrypt" + - onchanges: + - x509: etc_elasticfleet_agent_key + +efagentperms: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-agent.key + - mode: 640 + - group: 939 + +chownelasticfleetagentcrt: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-agent.crt + - mode: 640 + - user: 947 + - group: 939 + +chownelasticfleetagentkey: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-agent.key + - mode: 640 + - user: 947 + - group: 939 +# End -- Elastic Fleet Client Cert for Agent (Mutual Auth with Logstash Output) + +{% endif %} + +{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone'] %} +elasticfleet_kafka_key: + x509.private_key_managed: + - name: /etc/pki/elasticfleet-kafka.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/elasticfleet-kafka.key') -%} + - prereq: + - x509: elasticfleet_kafka_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +elasticfleet_kafka_crt: + x509.certificate_managed: + - name: /etc/pki/elasticfleet-kafka.crt + - ca_server: {{ CA.server }} + - signing_policy: kafka + - private_key: /etc/pki/elasticfleet-kafka.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + +elasticfleet_kafka_cert_perms: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-kafka.crt + - mode: 640 + - user: 947 + - group: 939 + +elasticfleet_kafka_key_perms: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-kafka.key + - mode: 640 + - user: 947 + - group: 939 +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load b/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load index ca260891f..e548c7f86 100644 --- a/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load +++ b/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load @@ -17,9 +17,9 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then # Third, configure Elastic Defend Integration seperately /usr/sbin/so-elastic-fleet-integration-policy-elastic-defend + # Initial Endpoints - for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/endpoints-initial/*.json - do + for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/endpoints-initial/*.json; do printf "\n\nInitial Endpoints Policy - Loading $INTEGRATION\n" elastic_fleet_integration_check "endpoints-initial" "$INTEGRATION" if [ -n "$INTEGRATION_ID" ]; then @@ -40,8 +40,7 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then done # Grid Nodes - General - for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_general/*.json - do + for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_general/*.json; do printf "\n\nGrid Nodes Policy_General - Loading $INTEGRATION\n" elastic_fleet_integration_check "so-grid-nodes_general" "$INTEGRATION" if [ -n "$INTEGRATION_ID" ]; then @@ -60,13 +59,9 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then fi fi done - if [[ "$RETURN_CODE" != "1" ]]; then - touch /opt/so/state/eaintegrations.txt - fi # Grid Nodes - Heavy - for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_heavy/*.json - do + for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/grid-nodes_heavy/*.json; do printf "\n\nGrid Nodes Policy_Heavy - Loading $INTEGRATION\n" elastic_fleet_integration_check "so-grid-nodes_heavy" "$INTEGRATION" if [ -n "$INTEGRATION_ID" ]; then @@ -78,22 +73,16 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then fi else printf "\n\nIntegration does not exist - Creating integration\n" - if [ "$NAME" != "elasticsearch-logs" ]; then - if ! elastic_fleet_integration_create "@$INTEGRATION"; then - echo -e "\nFailed to create integration for ${INTEGRATION##*/}" - RETURN_CODE=1 - continue - fi + if ! elastic_fleet_integration_create "@$INTEGRATION"; then + echo -e "\nFailed to create integration for ${INTEGRATION##*/}" + RETURN_CODE=1 + continue fi fi done - if [[ "$RETURN_CODE" != "1" ]]; then - touch /opt/so/state/eaintegrations.txt - fi # Fleet Server - Optional integrations - for INTEGRATION in /opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json - do + for INTEGRATION in /opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json; do if ! [ "$INTEGRATION" == "/opt/so/conf/elastic-fleet/integrations-optional/FleetServer*/*.json" ]; then FLEET_POLICY=`echo "$INTEGRATION"| cut -d'/' -f7` printf "\n\nFleet Server Policy - Loading $INTEGRATION\n" @@ -117,6 +106,8 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then fi fi done + + # Only create the state file if all policies were created/updated successfully if [[ "$RETURN_CODE" != "1" ]]; then touch /opt/so/state/eaintegrations.txt fi diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-grid-upgrade b/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-grid-upgrade index 449d26c99..0729531d3 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-grid-upgrade +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-agent-grid-upgrade @@ -14,7 +14,7 @@ if ! is_manager_node; then fi # Get current list of Grid Node Agents that need to be upgraded -RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/agents?perPage=20&page=1&kuery=NOT%20agent.version%20:%20%22{{ELASTICSEARCHDEFAULTS.elasticsearch.version}}%22%20and%20policy_id%20:%20%22so-grid-nodes_general%22&showInactive=false&getStatusSummary=true") +RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/agents?perPage=20&page=1&kuery=NOT%20agent.version%3A%20{{ELASTICSEARCHDEFAULTS.elasticsearch.version}}%20AND%20policy_id%3A%20so-grid-nodes_%2A&showInactive=false&getStatusSummary=true" --retry 3 --retry-delay 30 --fail 2>/dev/null) # Check to make sure that the server responded with good data - else, bail from script CHECKSUM=$(jq -r '.page' <<< "$RAW_JSON") diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-es-url-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-es-url-update index 3da6b3e78..17086bf1a 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-es-url-update +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-es-url-update @@ -26,7 +26,7 @@ function update_es_urls() { } # Get current list of Fleet Elasticsearch URLs -RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_elasticsearch') +RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_elasticsearch' --retry 3 --retry-delay 30 --fail 2>/dev/null) # Check to make sure that the server responded with good data - else, bail from script CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON") diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load index 01777e5da..8c0f627ef 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-optional-integrations-load @@ -86,7 +86,7 @@ if [[ -f $STATE_FILE_SUCCESS ]]; then latest_package_list=$(/usr/sbin/so-elastic-fleet-package-list) echo '{ "packages" : []}' > $BULK_INSTALL_PACKAGE_LIST rm -f $INSTALLED_PACKAGE_LIST - echo $latest_package_list | jq '{packages: [.items[] | {name: .name, latest_version: .version, installed_version: .savedObject.attributes.install_version, subscription: .conditions.elastic.subscription }]}' >> $INSTALLED_PACKAGE_LIST + echo $latest_package_list | jq '{packages: [.items[] | {name: .name, latest_version: .version, installed_version: .installationInfo.version, subscription: .conditions.elastic.subscription }]}' >> $INSTALLED_PACKAGE_LIST while read -r package; do # get package details diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-outputs-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-outputs-update index 58baadca5..f045bf753 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-outputs-update +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-outputs-update @@ -142,7 +142,7 @@ function update_kafka_outputs() { {% if GLOBALS.pipeline == "KAFKA" %} # Get current list of Kafka Outputs - RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_kafka') + RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_kafka' --retry 3 --retry-delay 30 --fail 2>/dev/null) # Check to make sure that the server responded with good data - else, bail from script CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON") @@ -168,7 +168,7 @@ function update_kafka_outputs() { {# If global pipeline isn't set to KAFKA then assume default of REDIS / logstash #} {% else %} # Get current list of Logstash Outputs - RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_logstash') + RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/outputs/so-manager_logstash' --retry 3 --retry-delay 30 --fail 2>/dev/null) # Check to make sure that the server responded with good data - else, bail from script CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON") diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup index 446fc6c9a..5e0dc0c69 100755 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup @@ -241,9 +241,11 @@ printf '%s\n'\ "" >> "$global_pillar_file" # Call Elastic-Fleet Salt State +printf "\nApplying elasticfleet state" salt-call state.apply elasticfleet queue=True # Generate installers & install Elastic Agent on the node so-elastic-agent-gen-installers +printf "\nApplying elasticfleet.install_agent_grid state" salt-call state.apply elasticfleet.install_agent_grid queue=True exit 0 diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-urls-update b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-urls-update index 5f7637cd3..d841b39e4 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-urls-update +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-urls-update @@ -23,7 +23,7 @@ function update_fleet_urls() { } # Get current list of Fleet Server URLs -RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/fleet_server_hosts/grid-default') +RAW_JSON=$(curl -K /opt/so/conf/elasticsearch/curl.config 'http://localhost:5601/api/fleet/fleet_server_hosts/grid-default' --retry 3 --retry-delay 30 --fail 2>/dev/null) # Check to make sure that the server responded with good data - else, bail from script CHECKSUM=$(jq -r '.item.id' <<< "$RAW_JSON") diff --git a/salt/elasticfleet/tools/sbin_jinja/so-kafka-fleet-output-policy b/salt/elasticfleet/tools/sbin_jinja/so-kafka-fleet-output-policy index d44a5cb6c..2e44a4a36 100644 --- a/salt/elasticfleet/tools/sbin_jinja/so-kafka-fleet-output-policy +++ b/salt/elasticfleet/tools/sbin_jinja/so-kafka-fleet-output-policy @@ -34,6 +34,11 @@ if [[ "$RETURN_CODE" != "0" ]]; then exit 1 fi +if [[ ! -f /etc/pki/elasticfleet-kafka.crt || ! -f /etc/pki/elasticfleet-kafka.key ]]; then + echo -e "\nKafka certificates not found, can't setup Elastic Fleet output policy for Kafka...\n" + exit 1 +fi + KAFKACRT=$(openssl x509 -in /etc/pki/elasticfleet-kafka.crt) KAFKAKEY=$(openssl rsa -in /etc/pki/elasticfleet-kafka.key) KAFKACA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt) @@ -47,7 +52,7 @@ if ! kafka_output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "http://l --arg KAFKACA "$KAFKACA" \ --arg MANAGER_IP "{{ GLOBALS.manager_ip }}:9092" \ --arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \ - '{"name":"grid-kafka", "id":"so-manager_kafka","type":"kafka","hosts":[ $MANAGER_IP ],"is_default":false,"is_default_monitoring":false,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topics":[{"topic":"default-securityonion"}],"headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}' + '{"name":"grid-kafka", "id":"so-manager_kafka","type":"kafka","hosts":[ $MANAGER_IP ],"is_default":false,"is_default_monitoring":false,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topic":"default-securityonion","headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}' ) if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/outputs" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then echo -e "\nFailed to setup Elastic Fleet output policy for Kafka...\n" @@ -67,7 +72,7 @@ elif kafka_output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "http://l --arg ENABLED_DISABLED "$ENABLED_DISABLED"\ --arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \ --argjson HOSTS "$HOSTS" \ - '{"name":"grid-kafka","type":"kafka","hosts":$HOSTS,"is_default":$ENABLED_DISABLED,"is_default_monitoring":$ENABLED_DISABLED,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topics":[{"topic":"default-securityonion"}],"headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}' + '{"name":"grid-kafka","type":"kafka","hosts":$HOSTS,"is_default":$ENABLED_DISABLED,"is_default_monitoring":$ENABLED_DISABLED,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topic":"default-securityonion","headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}' ) if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then echo -e "\nFailed to force update to Elastic Fleet output policy for Kafka...\n" diff --git a/salt/elasticsearch/ca.sls b/salt/elasticsearch/ca.sls index 188450311..39d33919c 100644 --- a/salt/elasticsearch/ca.sls +++ b/salt/elasticsearch/ca.sls @@ -26,14 +26,14 @@ catrustscript: GLOBALS: {{ GLOBALS }} {% endif %} -cacertz: +elasticsearch_cacerts: file.managed: - name: /opt/so/conf/ca/cacerts - source: salt://elasticsearch/cacerts - user: 939 - group: 939 -capemz: +elasticsearch_capems: file.managed: - name: /opt/so/conf/ca/tls-ca-bundle.pem - source: salt://elasticsearch/tls-ca-bundle.pem diff --git a/salt/elasticsearch/config.map.jinja b/salt/elasticsearch/config.map.jinja index cfbab8524..8eb62311c 100644 --- a/salt/elasticsearch/config.map.jinja +++ b/salt/elasticsearch/config.map.jinja @@ -6,8 +6,6 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} {% import_yaml 'elasticsearch/defaults.yaml' as ELASTICSEARCHDEFAULTS with context %} -{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} - {# this is a list of dicts containing hostname:ip for elasticsearch nodes that need to know about each other for cluster #} {% set ELASTICSEARCH_SEED_HOSTS = [] %} {% set node_data = salt['pillar.get']('elasticsearch:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %} @@ -36,14 +34,8 @@ {% endfor %} {% endif %} {% elif grains.id.split('_') | last == 'searchnode' %} - {% if HIGHLANDER %} - {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.roles.extend(['ml', 'master', 'transform']) %} - {% endif %} {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.update({'discovery': {'seed_hosts': [GLOBALS.manager]}}) %} {% endif %} -{% if HIGHLANDER %} - {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.xpack.ml.update({'enabled': true}) %} -{% endif %} {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.update({'name': GLOBALS.hostname}) %} {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.cluster.update({'name': GLOBALS.hostname}) %} diff --git a/salt/elasticsearch/config.sls b/salt/elasticsearch/config.sls index 147975bb1..41ef02164 100644 --- a/salt/elasticsearch/config.sls +++ b/salt/elasticsearch/config.sls @@ -5,17 +5,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} - -include: - - ssl - - elasticsearch.ca - {% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} vm.max_map_count: sysctl.present: - - value: 262144 + - value: {{ ELASTICSEARCHMERGED.vm.max_map_count }} # Add ES Group elasticsearchgroup: @@ -103,10 +98,6 @@ esrolesdir: - group: 939 - makedirs: True -eslibdir: - file.absent: - - name: /opt/so/conf/elasticsearch/lib - esingestdynamicconf: file.recurse: - name: /opt/so/conf/elasticsearch/ingest @@ -124,11 +115,6 @@ esingestconf: - group: 939 - show_changes: False -# Remove .fleet_final_pipeline-1 because we are using global@custom now -so-fleet-final-pipeline-remove: - file.absent: - - name: /opt/so/conf/elasticsearch/ingest/.fleet_final_pipeline-1 - # Auto-generate Elasticsearch ingest node pipelines from pillar {% for pipeline, config in ELASTICSEARCHMERGED.pipelines.items() %} es_ingest_conf_{{pipeline}}: diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index c9f77aa7d..d0ab0f959 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -1,11 +1,15 @@ elasticsearch: enabled: false - version: 8.18.8 + version: 9.0.8 index_clean: true + vm: + max_map_count: 1048576 config: action: destructive_requires_name: true cluster: + logsdb: + enabled: false routing: allocation: disk: @@ -115,7 +119,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - so-case* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -127,8 +131,6 @@ elasticsearch: match_mapping_type: string settings: index: - lifecycle: - name: so-case-logs mapping: total_fields: limit: 1500 @@ -139,14 +141,7 @@ elasticsearch: sort: field: '@timestamp' order: desc - policy: - phases: - hot: - actions: {} - min_age: 0ms so-common: - close: 30 - delete: 365 index_sorting: false index_template: composed_of: @@ -210,7 +205,9 @@ elasticsearch: - common-settings - common-dynamic-mappings - winlog-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-*-so* @@ -270,7 +267,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - so-detection* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -282,8 +279,6 @@ elasticsearch: match_mapping_type: string settings: index: - lifecycle: - name: so-detection-logs mapping: total_fields: limit: 1500 @@ -294,11 +289,6 @@ elasticsearch: sort: field: '@timestamp' order: desc - policy: - phases: - hot: - actions: {} - min_age: 0ms sos-backup: index_sorting: false index_template: @@ -458,7 +448,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - endgame* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -506,8 +496,6 @@ elasticsearch: priority: 50 min_age: 30d so-idh: - close: 30 - delete: 365 index_sorting: false index_template: composed_of: @@ -562,10 +550,13 @@ elasticsearch: - dtc-user_agent-mappings - common-settings - common-dynamic-mappings + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - - so-idh-* - priority: 500 + - logs-idh-so* + priority: 501 template: mappings: date_detection: false @@ -675,11 +666,13 @@ elasticsearch: - common-dynamic-mappings - winlog-mappings - hash-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-import-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -691,7 +684,6 @@ elasticsearch: match_mapping_type: string settings: index: - final_pipeline: .fleet_final_pipeline-1 lifecycle: name: so-import-logs mapping: @@ -735,7 +727,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - so-ip* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -750,19 +742,12 @@ elasticsearch: mapping: total_fields: limit: 1500 - lifecycle: - name: so-ip-mappings-logs number_of_replicas: 0 number_of_shards: 1 refresh_interval: 30s sort: field: '@timestamp' order: desc - policy: - phases: - hot: - actions: {} - min_age: 0ms so-items: index_sorting: false index_template: @@ -771,7 +756,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - .items-default-** - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -850,60 +835,18 @@ elasticsearch: priority: 50 min_age: 30d so-kratos: - close: 30 - delete: 365 index_sorting: false index_template: composed_of: - agent-mappings - dtc-agent-mappings - - base-mappings - - dtc-base-mappings - - client-mappings - - dtc-client-mappings - - container-mappings - - destination-mappings - - dtc-destination-mappings - - pb-override-destination-mappings - - dll-mappings - - dns-mappings - - dtc-dns-mappings - - ecs-mappings - - dtc-ecs-mappings - - error-mappings - event-mappings - - dtc-event-mappings - file-mappings - - dtc-file-mappings - - group-mappings - host-mappings - dtc-host-mappings - http-mappings - dtc-http-mappings - - log-mappings - metadata-mappings - - network-mappings - - dtc-network-mappings - - observer-mappings - - dtc-observer-mappings - - organization-mappings - - package-mappings - - process-mappings - - dtc-process-mappings - - related-mappings - - rule-mappings - - dtc-rule-mappings - - server-mappings - - service-mappings - - dtc-service-mappings - - source-mappings - - dtc-source-mappings - - pb-override-source-mappings - - threat-mappings - - tls-mappings - - url-mappings - - user_agent-mappings - - dtc-user_agent-mappings - common-settings - common-dynamic-mappings data_stream: @@ -912,7 +855,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - logs-kratos-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -960,8 +903,6 @@ elasticsearch: priority: 50 min_age: 30d so-hydra: - close: 30 - delete: 365 index_sorting: false index_template: composed_of: @@ -1022,7 +963,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - logs-hydra-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -1077,7 +1018,7 @@ elasticsearch: ignore_missing_component_templates: [] index_patterns: - .lists-default-** - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -1563,6 +1504,9 @@ elasticsearch: - so-fleet_integrations.ip_mappings-1 - so-fleet_globals-1 - so-fleet_agent_id_verification-1 + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: - logs-elastic_agent.cloudbeat@custom index_patterns: @@ -1798,6 +1742,9 @@ elasticsearch: - so-fleet_integrations.ip_mappings-1 - so-fleet_globals-1 - so-fleet_agent_id_verification-1 + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: - logs-elastic_agent.heartbeat@custom index_patterns: @@ -3057,8 +3004,6 @@ elasticsearch: priority: 50 min_age: 30d so-logs-soc: - close: 30 - delete: 365 index_sorting: false index_template: composed_of: @@ -3113,11 +3058,13 @@ elasticsearch: - dtc-user_agent-mappings - common-settings - common-dynamic-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-soc-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -3707,10 +3654,13 @@ elasticsearch: - vulnerability-mappings - common-settings - common-dynamic-mappings + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-logstash-default* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -4008,10 +3958,13 @@ elasticsearch: - vulnerability-mappings - common-settings - common-dynamic-mappings + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - - logs-redis-default* - priority: 500 + - logs-redis.log* + priority: 501 template: mappings: date_detection: false @@ -4122,11 +4075,13 @@ elasticsearch: - common-settings - common-dynamic-mappings - hash-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-strelka-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -4236,11 +4191,13 @@ elasticsearch: - common-settings - common-dynamic-mappings - hash-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-suricata-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -4350,11 +4307,13 @@ elasticsearch: - common-settings - common-dynamic-mappings - hash-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-suricata.alerts-* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -4464,11 +4423,13 @@ elasticsearch: - vulnerability-mappings - common-settings - common-dynamic-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-syslog-so* - priority: 500 + priority: 501 template: mappings: date_detection: false @@ -4580,11 +4541,13 @@ elasticsearch: - common-settings - common-dynamic-mappings - hash-mappings - data_stream: {} + data_stream: + allow_custom_routing: false + hidden: false ignore_missing_component_templates: [] index_patterns: - logs-zeek-so* - priority: 500 + priority: 501 template: mappings: date_detection: false diff --git a/salt/elasticsearch/enabled.sls b/salt/elasticsearch/enabled.sls index 49f34314b..29ab80329 100644 --- a/salt/elasticsearch/enabled.sls +++ b/salt/elasticsearch/enabled.sls @@ -6,7 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_NODES %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_SEED_HOSTS %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} @@ -14,6 +14,9 @@ {% from 'elasticsearch/template.map.jinja' import ES_INDEX_SETTINGS %} include: + - ca + - elasticsearch.ca + - elasticsearch.ssl - elasticsearch.config - elasticsearch.sostatus @@ -25,15 +28,15 @@ so-elasticsearch: - user: elasticsearch - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elasticsearch'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-elasticsearch'].ip }} - extra_hosts: {% for node in ELASTICSEARCH_NODES %} {% for hostname, ip in node.items() %} - {{hostname}}:{{ip}} {% endfor %} {% endfor %} - {% if DOCKER.containers['so-elasticsearch'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-elasticsearch'].extra_hosts %} + {% if DOCKERMERGED.containers['so-elasticsearch'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-elasticsearch'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} @@ -42,17 +45,19 @@ so-elasticsearch: - discovery.type=single-node {% endif %} - ES_JAVA_OPTS=-Xms{{ GLOBALS.elasticsearch.es_heap }} -Xmx{{ GLOBALS.elasticsearch.es_heap }} -Des.transport.cname_in_publish_address=true -Dlog4j2.formatMsgNoLookups=true - ulimits: - - memlock=-1:-1 - - nofile=65536:65536 - - nproc=4096 - {% if DOCKER.containers['so-elasticsearch'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-elasticsearch'].extra_env %} + {% if DOCKERMERGED.containers['so-elasticsearch'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-elasticsearch'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-elasticsearch'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-elasticsearch'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-elasticsearch'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-elasticsearch'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -61,11 +66,7 @@ so-elasticsearch: - /nsm/elasticsearch:/usr/share/elasticsearch/data:rw - /opt/so/log/elasticsearch:/var/log/elasticsearch:rw - /opt/so/conf/ca/cacerts:/usr/share/elasticsearch/jdk/lib/security/cacerts:ro - {% if GLOBALS.is_manager %} - - /etc/pki/ca.crt:/usr/share/elasticsearch/config/ca.crt:ro - {% else %} - /etc/pki/tls/certs/intca.crt:/usr/share/elasticsearch/config/ca.crt:ro - {% endif %} - /etc/pki/elasticsearch.crt:/usr/share/elasticsearch/config/elasticsearch.crt:ro - /etc/pki/elasticsearch.key:/usr/share/elasticsearch/config/elasticsearch.key:ro - /etc/pki/elasticsearch.p12:/usr/share/elasticsearch/config/elasticsearch.p12:ro @@ -76,28 +77,27 @@ so-elasticsearch: - {{ repo }}:{{ repo }}:rw {% endfor %} {% endif %} - {% if DOCKER.containers['so-elasticsearch'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-elasticsearch'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-elasticsearch'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-elasticsearch'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - watch: - - file: cacertz + - file: trusttheca + - x509: elasticsearch_crt + - x509: elasticsearch_key + - file: elasticsearch_cacerts - file: esyml - require: + - file: trusttheca + - x509: elasticsearch_crt + - x509: elasticsearch_key + - file: elasticsearch_cacerts - file: esyml - file: eslog4jfile - file: nsmesdir - file: eslogdir - - file: cacertz - - x509: /etc/pki/elasticsearch.crt - - x509: /etc/pki/elasticsearch.key - file: elasticp12perms - {% if GLOBALS.is_manager %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - cmd: auth_users_roles_inode - cmd: auth_users_inode diff --git a/salt/elasticsearch/files/ingest-dynamic/.gitkeep b/salt/elasticsearch/files/ingest-dynamic/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/salt/elasticsearch/files/ingest-dynamic/common b/salt/elasticsearch/files/ingest/common similarity index 95% rename from salt/elasticsearch/files/ingest-dynamic/common rename to salt/elasticsearch/files/ingest/common index 814d8d4d5..b7048cf3b 100644 --- a/salt/elasticsearch/files/ingest-dynamic/common +++ b/salt/elasticsearch/files/ingest/common @@ -1,5 +1,3 @@ -{%- set HIGHLANDER = salt['pillar.get']('global:highlander', False) -%} -{%- raw -%} { "description" : "common", "processors" : [ @@ -67,19 +65,7 @@ { "append": { "if": "ctx.dataset_tag_temp != null", "field": "tags", "value": "{{dataset_tag_temp.1}}" } }, { "grok": { "if": "ctx.http?.response?.status_code != null", "field": "http.response.status_code", "patterns": ["%{NUMBER:http.response.status_code:long} %{GREEDYDATA}"]} }, { "set": { "if": "ctx?.metadata?.kafka != null" , "field": "kafka.id", "value": "{{metadata.kafka.partition}}{{metadata.kafka.offset}}{{metadata.kafka.timestamp}}", "ignore_failure": true } }, - { "remove": { "field": [ "message2", "type", "fields", "category", "module", "dataset", "dataset_tag_temp", "event.dataset_temp" ], "ignore_missing": true, "ignore_failure": true } } -{%- endraw %} -{%- if HIGHLANDER %} - , - { - "pipeline": { - "name": "ecs" - } - } -{%- endif %} -{%- raw %} - , + { "remove": { "field": [ "message2", "type", "fields", "category", "module", "dataset", "dataset_tag_temp", "event.dataset_temp" ], "ignore_missing": true, "ignore_failure": true } }, { "pipeline": { "name": "global@custom", "ignore_missing_pipeline": true, "description": "[Fleet] Global pipeline for all data streams" } } ] } -{% endraw %} diff --git a/salt/elasticsearch/files/ingest/global@custom b/salt/elasticsearch/files/ingest/global@custom index 8e48eb0b9..bafb783a4 100644 --- a/salt/elasticsearch/files/ingest/global@custom +++ b/salt/elasticsearch/files/ingest/global@custom @@ -1,31 +1,212 @@ { - "version": 3, - "_meta": { - "managed_by": "securityonion", - "managed": true - }, - "description": "Custom pipeline for processing all incoming Fleet Agent documents. \n", - "processors": [ - { "set": { "ignore_failure": true, "field": "event.module", "value": "elastic_agent" } }, - { "split": { "if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')", "field": "event.dataset", "separator": "\\.", "target_field": "module_temp" } }, - { "split": { "if": "ctx.data_stream?.dataset != null && ctx.data_stream?.dataset.contains('.')", "field":"data_stream.dataset", "separator":"\\.", "target_field":"datastream_dataset_temp", "ignore_missing":true } }, - { "set": { "if": "ctx.module_temp != null", "override": true, "field": "event.module", "value": "{{module_temp.0}}" } }, - { "set": { "if": "ctx.datastream_dataset_temp != null && ctx.datastream_dataset_temp[0] == 'network_traffic'", "field":"event.module", "value":"{{ datastream_dataset_temp.0 }}", "ignore_failure":true, "ignore_empty_value":true, "description":"Fix EA network packet capture" } }, - { "gsub": { "if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')", "field": "event.dataset", "pattern": "^[^.]*.", "replacement": "", "target_field": "dataset_tag_temp" } }, - { "append": { "if": "ctx.dataset_tag_temp != null", "field": "tags", "value": "{{dataset_tag_temp}}", "allow_duplicates": false } }, - { "set": { "if": "ctx.network?.direction == 'egress'", "override": true, "field": "network.initiated", "value": "true" } }, - { "set": { "if": "ctx.network?.direction == 'ingress'", "override": true, "field": "network.initiated", "value": "false" } }, - { "set": { "if": "ctx.network?.type == 'ipv4'", "override": true, "field": "destination.ipv6", "value": "false" } }, - { "set": { "if": "ctx.network?.type == 'ipv6'", "override": true, "field": "destination.ipv6", "value": "true" } }, - { "set": { "if": "ctx.tags != null && ctx.tags.contains('import')", "override": true, "field": "data_stream.dataset", "value": "import" } }, - { "set": { "if": "ctx.tags != null && ctx.tags.contains('import')", "override": true, "field": "data_stream.namespace", "value": "so" } }, - { "community_id":{ "if": "ctx.event?.dataset == 'endpoint.events.network'", "ignore_failure":true } }, - { "set": { "if": "ctx.event?.module == 'fim'", "override": true, "field": "event.module", "value": "file_integrity" } }, - { "rename": { "if": "ctx.winlog?.provider_name == 'Microsoft-Windows-Windows Defender'", "ignore_missing": true, "field": "winlog.event_data.Threat Name", "target_field": "winlog.event_data.threat_name" } }, - { "set": { "if": "ctx?.metadata?.kafka != null" , "field": "kafka.id", "value": "{{metadata.kafka.partition}}{{metadata.kafka.offset}}{{metadata.kafka.timestamp}}", "ignore_failure": true } }, - { "set": { "if": "ctx.event?.dataset != null && ctx.event?.dataset == 'elasticsearch.server'", "field": "event.module", "value":"elasticsearch" }}, - {"append": {"field":"related.ip","value":["{{source.ip}}","{{destination.ip}}"],"allow_duplicates":false,"if":"ctx?.event?.dataset == 'endpoint.events.network' && ctx?.source?.ip != null","ignore_failure":true}}, - {"foreach": {"field":"host.ip","processor":{"append":{"field":"related.ip","value":"{{_ingest._value}}","allow_duplicates":false}},"if":"ctx?.event?.module == 'endpoint' && ctx?.host?.ip != null","ignore_missing":true, "description":"Extract IPs from Elastic Agent events (host.ip) and adds them to related.ip"}}, - { "remove": { "field": [ "message2", "type", "fields", "category", "module", "dataset", "event.dataset_temp", "dataset_tag_temp", "module_temp", "datastream_dataset_temp" ], "ignore_missing": true, "ignore_failure": true } } - ] -} + "version": 3, + "_meta": { + "managed_by": "securityonion", + "managed": true + }, + "description": "Custom pipeline for processing all incoming Fleet Agent documents. \n", + "processors": [ + { + "set": { + "ignore_failure": true, + "field": "event.module", + "value": "elastic_agent" + } + }, + { + "split": { + "if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')", + "field": "event.dataset", + "separator": "\\.", + "target_field": "module_temp" + } + }, + { + "split": { + "if": "ctx.data_stream?.dataset != null && ctx.data_stream?.dataset.contains('.')", + "field": "data_stream.dataset", + "separator": "\\.", + "target_field": "datastream_dataset_temp", + "ignore_missing": true + } + }, + { + "set": { + "if": "ctx.module_temp != null", + "override": true, + "field": "event.module", + "value": "{{module_temp.0}}" + } + }, + { + "set": { + "if": "ctx.datastream_dataset_temp != null && ctx.datastream_dataset_temp[0] == 'network_traffic'", + "field": "event.module", + "value": "{{ datastream_dataset_temp.0 }}", + "ignore_failure": true, + "ignore_empty_value": true, + "description": "Fix EA network packet capture" + } + }, + { + "gsub": { + "if": "ctx.event?.dataset != null && ctx.event.dataset.contains('.')", + "field": "event.dataset", + "pattern": "^[^.]*.", + "replacement": "", + "target_field": "dataset_tag_temp" + } + }, + { + "append": { + "if": "ctx.dataset_tag_temp != null", + "field": "tags", + "value": "{{dataset_tag_temp}}", + "allow_duplicates": false + } + }, + { + "set": { + "if": "ctx.network?.direction == 'egress'", + "override": true, + "field": "network.initiated", + "value": "true" + } + }, + { + "set": { + "if": "ctx.network?.direction == 'ingress'", + "override": true, + "field": "network.initiated", + "value": "false" + } + }, + { + "set": { + "if": "ctx.network?.type == 'ipv4'", + "override": true, + "field": "destination.ipv6", + "value": "false" + } + }, + { + "set": { + "if": "ctx.network?.type == 'ipv6'", + "override": true, + "field": "destination.ipv6", + "value": "true" + } + }, + { + "set": { + "if": "ctx.tags != null && ctx.tags.contains('import')", + "override": true, + "field": "data_stream.dataset", + "value": "import" + } + }, + { + "set": { + "if": "ctx.tags != null && ctx.tags.contains('import')", + "override": true, + "field": "data_stream.namespace", + "value": "so" + } + }, + { + "community_id": { + "if": "ctx.event?.dataset == 'endpoint.events.network'", + "ignore_failure": true + } + }, + { + "set": { + "if": "ctx.event?.module == 'fim'", + "override": true, + "field": "event.module", + "value": "file_integrity" + } + }, + { + "rename": { + "if": "ctx.winlog?.provider_name == 'Microsoft-Windows-Windows Defender'", + "ignore_missing": true, + "field": "winlog.event_data.Threat Name", + "target_field": "winlog.event_data.threat_name" + } + }, + { + "set": { + "if": "ctx?.metadata?.kafka != null", + "field": "kafka.id", + "value": "{{metadata.kafka.partition}}{{metadata.kafka.offset}}{{metadata.kafka.timestamp}}", + "ignore_failure": true + } + }, + { + "set": { + "if": "ctx.event?.dataset != null && ctx.event?.dataset == 'elasticsearch.server'", + "field": "event.module", + "value": "elasticsearch" + } + }, + { + "append": { + "field": "related.ip", + "value": [ + "{{source.ip}}", + "{{destination.ip}}" + ], + "allow_duplicates": false, + "if": "ctx?.event?.dataset == 'endpoint.events.network' && ctx?.source?.ip != null", + "ignore_failure": true + } + }, + { + "foreach": { + "field": "host.ip", + "processor": { + "append": { + "field": "related.ip", + "value": "{{_ingest._value}}", + "allow_duplicates": false + } + }, + "if": "ctx?.event?.module == 'endpoint' && ctx?.host?.ip != null", + "ignore_missing": true, + "description": "Extract IPs from Elastic Agent events (host.ip) and adds them to related.ip" + } + }, + { + "pipeline": { + "name": ".fleet_final_pipeline-1", + "ignore_missing_pipeline": true + } + }, + { + "remove": { + "field": "event.agent_id_status", + "ignore_missing": true, + "if": "ctx?.event?.agent_id_status == 'auth_metadata_missing'" + } + }, + { + "remove": { + "field": [ + "message2", + "type", + "fields", + "category", + "module", + "dataset", + "event.dataset_temp", + "dataset_tag_temp", + "module_temp", + "datastream_dataset_temp" + ], + "ignore_missing": true, + "ignore_failure": true + } + } + ] +} \ No newline at end of file diff --git a/salt/elasticsearch/files/ingest/kratos b/salt/elasticsearch/files/ingest/kratos index 9551dad24..b3410d9fd 100644 --- a/salt/elasticsearch/files/ingest/kratos +++ b/salt/elasticsearch/files/ingest/kratos @@ -1,9 +1,98 @@ { - "description" : "kratos", - "processors" : [ - {"set":{"field":"audience","value":"access","override":false,"ignore_failure":true}}, - {"set":{"field":"event.dataset","ignore_empty_value":true,"ignore_failure":true,"value":"kratos.{{{audience}}}","media_type":"text/plain"}}, - {"set":{"field":"event.action","ignore_failure":true,"copy_from":"msg" }}, - { "pipeline": { "name": "common" } } - ] + "description": "kratos", + "processors": [ + { + "set": { + "field": "audience", + "value": "access", + "override": false, + "ignore_failure": true + } + }, + { + "set": { + "field": "event.dataset", + "ignore_empty_value": true, + "ignore_failure": true, + "value": "kratos.{{{audience}}}", + "media_type": "text/plain" + } + }, + { + "set": { + "field": "event.action", + "ignore_failure": true, + "copy_from": "msg" + } + }, + { + "rename": { + "field": "http_request", + "target_field": "http.request", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "http_response", + "target_field": "http.response", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "http.request.path", + "target_field": "http.uri", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "http.request.method", + "target_field": "http.method", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "http.request.method", + "target_field": "http.method", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "http.request.query", + "target_field": "http.query", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "http.request.headers.user-agent", + "target_field": "http.useragent", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "rename": { + "field": "file", + "target_field": "file.path", + "ignore_failure": true, + "ignore_missing": true + } + }, + { + "pipeline": { + "name": "common" + } + } + ] } \ No newline at end of file diff --git a/salt/elasticsearch/files/ingest/suricata.common b/salt/elasticsearch/files/ingest/suricata.common index 7b2dc7eeb..887d10f86 100644 --- a/salt/elasticsearch/files/ingest/suricata.common +++ b/salt/elasticsearch/files/ingest/suricata.common @@ -22,6 +22,12 @@ "ignore_failure": true } }, + { + "lowercase": { + "field": "network.transport", + "ignore_failure": true + } + }, { "rename": { "field": "message2.in_iface", diff --git a/salt/elasticsearch/files/ingest/zeek.websocket b/salt/elasticsearch/files/ingest/zeek.websocket new file mode 100644 index 000000000..3f93f1cc3 --- /dev/null +++ b/salt/elasticsearch/files/ingest/zeek.websocket @@ -0,0 +1,18 @@ +{ + "description" : "zeek.websocket", + "processors" : [ + { "set": { "field": "event.dataset", "value": "websocket" } }, + { "remove": { "field": ["host"], "ignore_failure": true } }, + { "json": { "field": "message", "target_field": "message2", "ignore_failure": true } }, + { "rename": { "field": "message2.host", "target_field": "websocket.host", "ignore_missing": true } }, + { "rename": { "field": "message2.uri", "target_field": "websocket.uri", "ignore_missing": true } }, + { "rename": { "field": "message2.user_agent", "target_field": "websocket.user_agent", "ignore_missing": true } }, + { "rename": { "field": "message2.subprotocol", "target_field": "websocket.subprotocol", "ignore_missing": true } }, + { "rename": { "field": "message2.client_protocols", "target_field": "websocket.client_protocols", "ignore_missing": true } }, + { "rename": { "field": "message2.client_extensions", "target_field": "websocket.client_extensions", "ignore_missing": true } }, + { "rename": { "field": "message2.server_extensions", "target_field": "websocket.server_extensions", "ignore_missing": true } }, + { "remove": { "field": "message2.tags", "ignore_failure": true } }, + { "set": { "field": "network.transport", "value": "tcp" } }, + { "pipeline": { "name": "zeek.common" } } + ] +} diff --git a/salt/elasticsearch/soc_elasticsearch.yaml b/salt/elasticsearch/soc_elasticsearch.yaml index 7fd4f8329..b96c58dbe 100644 --- a/salt/elasticsearch/soc_elasticsearch.yaml +++ b/salt/elasticsearch/soc_elasticsearch.yaml @@ -1,8 +1,9 @@ elasticsearch: enabled: description: Enables or disables the Elasticsearch process. This process provides the log event storage system. WARNING - Disabling this process is unsupported. + forcedType: bool advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch version: description: "This specifies the version of the following containers: so-elastic-fleet-package-registry, so-elastic-agent, so-elastic-fleet, so-kibana, so-logstash and so-elasticsearch. Modifying this value in the Elasticsearch defaults.yaml will result in catastrophic grid failure." readonly: True @@ -10,15 +11,20 @@ elasticsearch: advanced: True esheap: description: Specify the memory heap size in (m)egabytes for Elasticsearch. - helpLink: elasticsearch.html + helpLink: elasticsearch index_clean: description: Determines if indices should be considered for deletion by available disk space in the cluster. Otherwise, indices will only be deleted by the age defined in the ILM settings. This setting only applies to EVAL, STANDALONE, and HEAVY NODE installations. Other installations can only use ILM settings. forcedType: bool - helpLink: elasticsearch.html + helpLink: elasticsearch + vm: + max_map_count: + description: The maximum number of memory map areas a process may use. Elasticsearch uses a mmapfs directory by default to store its indices. The default operating system limits on mmap counts could be too low, which may result in out of memory exceptions. + forcedType: int + helpLink: elasticsearch retention: retention_pct: decription: Total percentage of space used by Elasticsearch for multi node clusters - helpLink: elasticsearch.html + helpLink: elasticsearch global: True config: cluster: @@ -26,48 +32,102 @@ elasticsearch: description: The name of the Security Onion Elasticsearch cluster, for identification purposes. readonly: True global: True - helpLink: elasticsearch.html + helpLink: elasticsearch + logsdb: + enabled: + description: Enables or disables the Elasticsearch logsdb index mode. When enabled, most logs-* datastreams will convert to logsdb from standard after rolling over. + forcedType: bool + global: True + advanced: True + helpLink: elasticsearch routing: allocation: disk: - threshold_enabled: + threshold_enabled: description: Specifies whether the Elasticsearch node will monitor the available disk space for low disk space conditions and take action to protect the cluster. - helpLink: elasticsearch.html + forcedType: bool + helpLink: elasticsearch watermark: low: description: The lower percentage of used disk space representing a healthy node. - helpLink: elasticsearch.html + helpLink: elasticsearch high: description: The higher percentage of used disk space representing an unhealthy node. - helpLink: elasticsearch.html + helpLink: elasticsearch flood_stage: description: The max percentage of used disk space that will cause the node to take protective actions, such as blocking incoming events. - helpLink: elasticsearch.html + helpLink: elasticsearch + action: + destructive_requires_name: + description: Requires explicit index names when deleting indices. Prevents accidental deletion of indices via wildcard patterns. + advanced: True + forcedType: bool + helpLink: elasticsearch script: - max_compilations_rate: + max_compilations_rate: description: Max rate of script compilations permitted in the Elasticsearch cluster. Larger values will consume more resources. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch indices: + id_field_data: + enabled: + description: Enables or disables loading of field data on the _id field. + advanced: True + forcedType: bool + helpLink: elasticsearch query: bool: - max_clause_count: + max_clause_count: description: Max number of boolean clauses per query. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch + xpack: + ml: + enabled: + description: Enables or disables machine learning on the node. + forcedType: bool + advanced: True + helpLink: elasticsearch + security: + enabled: + description: Enables or disables Elasticsearch security features. + forcedType: bool + advanced: True + helpLink: elasticsearch + authc: + anonymous: + authz_exception: + description: Controls whether an authorization exception is thrown when anonymous user does not have the required privileges. + advanced: True + forcedType: bool + helpLink: elasticsearch + http: + ssl: + enabled: + description: Enables or disables TLS/SSL for the HTTP layer. + advanced: True + forcedType: bool + helpLink: elasticsearch + transport: + ssl: + enabled: + description: Enables or disables TLS/SSL for the transport layer. + advanced: True + forcedType: bool + helpLink: elasticsearch pipelines: custom001: &pipelines description: description: Description of the ingest node pipeline global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch processors: description: Processors for the ingest node pipeline global: True advanced: True multiline: True - helpLink: elasticsearch.html + helpLink: elasticsearch custom002: *pipelines custom003: *pipelines custom004: *pipelines @@ -77,13 +137,6 @@ elasticsearch: custom008: *pipelines custom009: *pipelines custom010: *pipelines - managed_integrations: - description: List of integrations to add into SOC config UI. Enter the full or partial integration name. Eg. 1password, 1pass - forcedType: "[]string" - multiline: True - global: True - advanced: True - helpLink: elasticsearch.html index_settings: global_overrides: index_template: @@ -94,24 +147,24 @@ elasticsearch: description: Number of replicas required for all indices. Multiple replicas protects against data loss, but also increases storage costs. This setting will be applied to all indices. forcedType: int global: True - helpLink: elasticsearch.html + helpLink: elasticsearch refresh_interval: description: Seconds between index refreshes. Shorter intervals can cause query performance to suffer since this is a synchronous and resource-intensive operation. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch number_of_shards: description: Number of shards required for this index. Using multiple shards increases fault tolerance, but also increases storage and network costs. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch sort: field: description: The field to sort by. Must set index_sorting to True. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch order: description: The order to sort by. Must set index_sorting to True. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch policy: phases: hot: @@ -121,16 +174,16 @@ elasticsearch: description: Priority of index. This is used for recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities. forcedType: int global: True - helpLink: elasticsearch.html + helpLink: elasticsearch rollover: max_age: description: Maximum age of index. Once an index reaches this limit, it will be rolled over into a new index. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch max_primary_shard_size: description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch shrink: method: description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size. @@ -178,13 +231,13 @@ elasticsearch: regex: ^[0-9]{1,5}d$ forcedType: string global: True - helpLink: elasticsearch.html + helpLink: elasticsearch actions: set_priority: priority: description: Used for index recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities. global: True - helpLink: elasticsearch.html + helpLink: elasticsearch allocate: number_of_replicas: description: Set the number of replicas. Remains the same as the previous phase by default. @@ -197,14 +250,14 @@ elasticsearch: regex: ^[0-9]{1,5}d$ forcedType: string global: True - helpLink: elasticsearch.html + helpLink: elasticsearch actions: set_priority: priority: description: Priority of index. This is used for recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities. forcedType: int global: True - helpLink: elasticsearch.html + helpLink: elasticsearch shrink: method: description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size. @@ -257,13 +310,14 @@ elasticsearch: regex: ^[0-9]{1,5}d$ forcedType: string global: True - helpLink: elasticsearch.html + helpLink: elasticsearch so-logs: &indexSettings - index_sorting: + index_sorting: description: Sorts the index by event time, at the cost of additional processing resource consumption. + forcedType: bool global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch index_template: index_patterns: description: Patterns for matching multiple indices or tables. @@ -271,7 +325,7 @@ elasticsearch: multiline: True global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch template: settings: index: @@ -280,35 +334,35 @@ elasticsearch: forcedType: int global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch mapping: total_fields: limit: description: Max number of fields that can exist on a single index. Larger values will consume more resources. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch refresh_interval: description: Seconds between index refreshes. Shorter intervals can cause query performance to suffer since this is a synchronous and resource-intensive operation. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch number_of_shards: description: Number of shards required for this index. Using multiple shards increases fault tolerance, but also increases storage and network costs. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch sort: field: description: The field to sort by. Must set index_sorting to True. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch order: description: The order to sort by. Must set index_sorting to True. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch mappings: _meta: package: @@ -316,43 +370,43 @@ elasticsearch: description: Meta settings for the mapping. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch managed_by: description: Meta settings for the mapping. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch managed: description: Meta settings for the mapping. forcedType: bool global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch composed_of: description: The index template is composed of these component templates. forcedType: "[]string" global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch priority: description: The priority of the index template. forcedType: int global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch data_stream: hidden: description: Hide the data stream. forcedType: bool global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch allow_custom_routing: description: Allow custom routing for the data stream. forcedType: bool global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch policy: phases: hot: @@ -360,7 +414,7 @@ elasticsearch: description: Minimum age of index. This determines when the index should be moved to the hot tier. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch actions: set_priority: priority: @@ -368,18 +422,18 @@ elasticsearch: forcedType: int global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch rollover: max_age: description: Maximum age of index. Once an index reaches this limit, it will be rolled over into a new index. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch max_primary_shard_size: description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch shrink: method: description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size. @@ -428,7 +482,7 @@ elasticsearch: forcedType: string global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch actions: set_priority: priority: @@ -436,18 +490,18 @@ elasticsearch: forcedType: int global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch rollover: max_age: description: Maximum age of index. Once an index reaches this limit, it will be rolled over into a new index. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch max_primary_shard_size: description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch shrink: method: description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size. @@ -501,7 +555,7 @@ elasticsearch: forcedType: string global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch actions: set_priority: priority: @@ -509,7 +563,7 @@ elasticsearch: forcedType: int global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch allocate: number_of_replicas: description: Set the number of replicas. Remains the same as the previous phase by default. @@ -523,25 +577,25 @@ elasticsearch: forcedType: string global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch _meta: package: name: description: Meta settings for the mapping. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch managed_by: description: Meta settings for the mapping. global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch managed: description: Meta settings for the mapping. forcedType: bool global: True advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch so-logs-system_x_auth: *indexSettings so-logs-system_x_syslog: *indexSettings so-logs-system_x_system: *indexSettings @@ -604,20 +658,21 @@ elasticsearch: so-metrics-fleet_server_x_agent_status: &fleetMetricsSettings index_sorting: description: Sorts the index by event time, at the cost of additional processing resource consumption. + forcedType: bool advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch index_template: ignore_missing_component_templates: description: Ignore component templates if they aren't in Elasticsearch. advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch index_patterns: description: Patterns for matching multiple indices or tables. advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch template: settings: index: @@ -625,33 +680,35 @@ elasticsearch: description: Type of mode used for this index. Time series indices can be used for metrics to reduce necessary storage. advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch number_of_replicas: description: Number of replicas required for this index. Multiple replicas protects against data loss, but also increases storage costs. advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch composed_of: description: The index template is composed of these component templates. advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch priority: description: The priority of the index template. advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch data_stream: hidden: description: Hide the data stream. + forcedType: bool advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch allow_custom_routing: description: Allow custom routing for the data stream. + forcedType: bool advanced: True readonly: True - helpLink: elasticsearch.html + helpLink: elasticsearch so-metrics-fleet_server_x_agent_versions: *fleetMetricsSettings so_roles: so-manager: &soroleSettings @@ -662,7 +719,7 @@ elasticsearch: forcedType: "[]string" global: False advanced: True - helpLink: elasticsearch.html + helpLink: elasticsearch so-managersearch: *soroleSettings so-standalone: *soroleSettings so-searchnode: *soroleSettings diff --git a/salt/elasticsearch/ssl.sls b/salt/elasticsearch/ssl.sls new file mode 100644 index 000000000..a2d327830 --- /dev/null +++ b/salt/elasticsearch/ssl.sls @@ -0,0 +1,66 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/map.jinja' import CA %} + +# Create a cert for elasticsearch +elasticsearch_key: + x509.private_key_managed: + - name: /etc/pki/elasticsearch.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/elasticsearch.key') -%} + - prereq: + - x509: /etc/pki/elasticsearch.crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +elasticsearch_crt: + x509.certificate_managed: + - name: /etc/pki/elasticsearch.crt + - ca_server: {{ CA.server }} + - signing_policy: registry + - private_key: /etc/pki/elasticsearch.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + cmd.run: + - name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/elasticsearch.key -in /etc/pki/elasticsearch.crt -export -out /etc/pki/elasticsearch.p12 -nodes -passout pass:" + - onchanges: + - x509: /etc/pki/elasticsearch.key + +elastickeyperms: + file.managed: + - replace: False + - name: /etc/pki/elasticsearch.key + - mode: 640 + - group: 930 + +elasticp12perms: + file.managed: + - replace: False + - name: /etc/pki/elasticsearch.p12 + - mode: 640 + - group: 930 + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticsearch/templates/component/ecs/dns.json b/salt/elasticsearch/templates/component/ecs/dns.json index 321a061f5..9cafac072 100644 --- a/salt/elasticsearch/templates/component/ecs/dns.json +++ b/salt/elasticsearch/templates/component/ecs/dns.json @@ -1,91 +1,103 @@ { - "_meta": { - "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-dns.html", - "ecs_version": "1.12.2" - }, - "template": { - "mappings": { - "properties": { - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" + "_meta": { + "documentation": "https://www.elastic.co/guide/en/ecs/current/ecs-dns.html", + "ecs_version": "1.12.2" + }, + "template": { + "mappings": { + "properties": { + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + }, + "type": "object" + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "query": { + "properties" :{ + "type":{ + "ignore_above": 1024, + "type": "keyword" + }, + "type_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } } - }, - "type": "object" - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" } - } } - } } - } } \ No newline at end of file diff --git a/salt/elasticsearch/templates/component/ecs/file.json b/salt/elasticsearch/templates/component/ecs/file.json index 3da5ee86a..dfd96c2b5 100644 --- a/salt/elasticsearch/templates/component/ecs/file.json +++ b/salt/elasticsearch/templates/component/ecs/file.json @@ -15,6 +15,13 @@ "ignore_above": 1024, "type": "keyword" }, + "bytes": { + "properties": { + "missing": { + "type": "long" + } + } + }, "code_signature": { "properties": { "digest_algorithm": { diff --git a/salt/elasticsearch/templates/component/elastic-agent/so-fleet_agent_id_verification-1.json b/salt/elasticsearch/templates/component/elastic-agent/so-fleet_agent_id_verification-1.json index 99b3aa871..46e16bb44 100644 --- a/salt/elasticsearch/templates/component/elastic-agent/so-fleet_agent_id_verification-1.json +++ b/salt/elasticsearch/templates/component/elastic-agent/so-fleet_agent_id_verification-1.json @@ -2,7 +2,7 @@ "template": { "settings": { "index": { - "final_pipeline": ".fleet_final_pipeline-1" + "final_pipeline": "global@custom" } }, "mappings": { diff --git a/salt/elasticsearch/tools/sbin_jinja/so-catrust b/salt/elasticsearch/tools/sbin_jinja/so-catrust index 16fd3ffdb..14f9e5ca1 100644 --- a/salt/elasticsearch/tools/sbin_jinja/so-catrust +++ b/salt/elasticsearch/tools/sbin_jinja/so-catrust @@ -14,8 +14,9 @@ set -e # Check to see if we have extracted the ca cert. if [ ! -f /opt/so/saltstack/local/salt/elasticsearch/cacerts ]; then docker run -v /etc/pki/ca.crt:/etc/ssl/ca.crt --name so-elasticsearchca --user root --entrypoint jdk/bin/keytool {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elasticsearch:$ELASTIC_AGENT_TARBALL_VERSION -keystore /usr/share/elasticsearch/jdk/lib/security/cacerts -alias SOSCA -import -file /etc/ssl/ca.crt -storepass changeit -noprompt - docker cp so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/elasticsearch/cacerts - docker cp so-elasticsearchca:/etc/ssl/certs/ca-certificates.crt /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem + # Make sure symbolic links are followed when copying from container + docker cp -L so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/elasticsearch/cacerts + docker cp -L so-elasticsearchca:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem docker rm so-elasticsearchca echo "" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem echo "sosca" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem diff --git a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load index 4ac1b4d5f..ad3fe1344 100755 --- a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load +++ b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-templates-load @@ -121,7 +121,7 @@ if [ ! -f $STATE_FILE_SUCCESS ]; then echo "Loading Security Onion index templates..." shopt -s extglob {% if GLOBALS.role == 'so-heavynode' %} - pattern="!(*1password*|*aws*|*azure*|*cloudflare*|*elastic_agent*|*fim*|*github*|*google*|*osquery*|*system*|*windows*)" + pattern="!(*1password*|*aws*|*azure*|*cloudflare*|*elastic_agent*|*fim*|*github*|*google*|*osquery*|*system*|*windows*|*endpoint*|*elasticsearch*|*generic*|*fleet_server*|*soc*)" {% else %} pattern="*" {% endif %} diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index cf7ae01a6..8bf0c2af1 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -27,14 +27,12 @@ iptables_config: - source: salt://firewall/iptables.jinja - template: jinja -{% if grains.os_family == 'RedHat' %} disable_firewalld: service.dead: - name: firewalld - enable: False - require: - file: iptables_config -{% endif %} iptables_restore: cmd.run: @@ -44,7 +42,6 @@ iptables_restore: - onlyif: - iptables-restore --test {{ iptmap.configfile }} -{% if grains.os_family == 'RedHat' %} enable_firewalld: service.running: - name: firewalld @@ -52,7 +49,6 @@ enable_firewalld: - onfail: - file: iptables_config - cmd: iptables_restore -{% endif %} {% else %} diff --git a/salt/firewall/ipt.map.jinja b/salt/firewall/ipt.map.jinja index 629c1bdd8..596a8af4e 100644 --- a/salt/firewall/ipt.map.jinja +++ b/salt/firewall/ipt.map.jinja @@ -1,14 +1,6 @@ -{% set iptmap = salt['grains.filter_by']({ - 'Debian': { - 'service': 'netfilter-persistent', - 'iptpkg': 'iptables', - 'persistpkg': 'iptables-persistent', - 'configfile': '/etc/iptables/rules.v4' - }, - 'RedHat': { - 'service': 'iptables', - 'iptpkg': 'iptables-nft', - 'persistpkg': 'iptables-nft-services', - 'configfile': '/etc/sysconfig/iptables' - }, -}) %} +{% set iptmap = { + 'service': 'iptables', + 'iptpkg': 'iptables-nft', + 'persistpkg': 'iptables-nft-services', + 'configfile': '/etc/sysconfig/iptables' +} %} diff --git a/salt/firewall/iptables.jinja b/salt/firewall/iptables.jinja index acb6b0eaf..91cfd92ec 100644 --- a/salt/firewall/iptables.jinja +++ b/salt/firewall/iptables.jinja @@ -1,5 +1,5 @@ {%- from 'vars/globals.map.jinja' import GLOBALS %} -{%- from 'docker/docker.map.jinja' import DOCKER %} +{%- from 'docker/docker.map.jinja' import DOCKERMERGED %} {%- from 'firewall/map.jinja' import FIREWALL_MERGED %} {%- set role = GLOBALS.role.split('-')[1] %} {%- from 'firewall/containers.map.jinja' import NODE_CONTAINERS %} @@ -8,9 +8,9 @@ {%- set D1 = [] %} {%- set D2 = [] %} {%- for container in NODE_CONTAINERS %} -{%- set IP = DOCKER.containers[container].ip %} -{%- if DOCKER.containers[container].port_bindings is defined %} -{%- for binding in DOCKER.containers[container].port_bindings %} +{%- set IP = DOCKERMERGED.containers[container].ip %} +{%- if DOCKERMERGED.containers[container].port_bindings is defined %} +{%- for binding in DOCKERMERGED.containers[container].port_bindings %} {#- cant split int so we convert to string #} {%- set binding = binding|string %} {#- split the port binding by /. if proto not specified, default is tcp #} @@ -33,13 +33,13 @@ {%- set hostPort = bsa[0] %} {%- set containerPort = bsa[1] %} {%- endif %} -{%- do PR.append("-A POSTROUTING -s " ~ DOCKER.containers[container].ip ~ "/32 -d " ~ DOCKER.containers[container].ip ~ "/32 -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ containerPort ~ " -j MASQUERADE") %} +{%- do PR.append("-A POSTROUTING -s " ~ DOCKERMERGED.containers[container].ip ~ "/32 -d " ~ DOCKERMERGED.containers[container].ip ~ "/32 -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ containerPort ~ " -j MASQUERADE") %} {%- if bindip | length and bindip != '0.0.0.0' %} -{%- do D1.append("-A DOCKER -d " ~ bindip ~ "/32 ! -i sobridge -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ hostPort ~ " -j DNAT --to-destination " ~ DOCKER.containers[container].ip ~ ":" ~ containerPort) %} +{%- do D1.append("-A DOCKER -d " ~ bindip ~ "/32 ! -i sobridge -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ hostPort ~ " -j DNAT --to-destination " ~ DOCKERMERGED.containers[container].ip ~ ":" ~ containerPort) %} {%- else %} -{%- do D1.append("-A DOCKER ! -i sobridge -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ hostPort ~ " -j DNAT --to-destination " ~ DOCKER.containers[container].ip ~ ":" ~ containerPort) %} +{%- do D1.append("-A DOCKER ! -i sobridge -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ hostPort ~ " -j DNAT --to-destination " ~ DOCKERMERGED.containers[container].ip ~ ":" ~ containerPort) %} {%- endif %} -{%- do D2.append("-A DOCKER -d " ~ DOCKER.containers[container].ip ~ "/32 ! -i sobridge -o sobridge -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ containerPort ~ " -j ACCEPT") %} +{%- do D2.append("-A DOCKER -d " ~ DOCKERMERGED.containers[container].ip ~ "/32 ! -i sobridge -o sobridge -p " ~ proto ~ " -m " ~ proto ~ " --dport " ~ containerPort ~ " -j ACCEPT") %} {%- endfor %} {%- endif %} {%- endfor %} @@ -52,7 +52,7 @@ :DOCKER - [0:0] -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER --A POSTROUTING -s {{DOCKER.range}} ! -o sobridge -j MASQUERADE +-A POSTROUTING -s {{DOCKERMERGED.range}} ! -o sobridge -j MASQUERADE {%- for rule in PR %} {{ rule }} {%- endfor %} diff --git a/salt/firewall/map.jinja b/salt/firewall/map.jinja index 8bd0512ec..58d8c189d 100644 --- a/salt/firewall/map.jinja +++ b/salt/firewall/map.jinja @@ -1,11 +1,11 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% import_yaml 'firewall/defaults.yaml' as FIREWALL_DEFAULT %} {# add our ip to self #} {% do FIREWALL_DEFAULT.firewall.hostgroups.self.append(GLOBALS.node_ip) %} {# add dockernet range #} -{% do FIREWALL_DEFAULT.firewall.hostgroups.dockernet.append(DOCKER.range) %} +{% do FIREWALL_DEFAULT.firewall.hostgroups.dockernet.append(DOCKERMERGED.range) %} {% if GLOBALS.role == 'so-idh' %} {% from 'idh/opencanary_config.map.jinja' import IDH_PORTGROUPS %} diff --git a/salt/firewall/soc_firewall.yaml b/salt/firewall/soc_firewall.yaml index 8aa42cd05..a5181e50f 100644 --- a/salt/firewall/soc_firewall.yaml +++ b/salt/firewall/soc_firewall.yaml @@ -3,7 +3,7 @@ firewall: analyst: &hostgroupsettings description: List of IP or CIDR blocks to allow access to this hostgroup. forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall multiline: True regex: ^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?)?$ regexFailureMessage: You must enter a valid IP address or CIDR. @@ -11,7 +11,7 @@ firewall: anywhere: &hostgroupsettingsadv description: List of IP or CIDR blocks to allow access to this hostgroup. forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall multiline: True advanced: True regex: ^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?)?$ @@ -22,7 +22,7 @@ firewall: dockernet: &ROhostgroupsettingsadv description: List of IP or CIDR blocks to allow access to this hostgroup. forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall multiline: True advanced: True readonly: True @@ -53,7 +53,7 @@ firewall: customhostgroup0: &customhostgroupsettings description: List of IP or CIDR blocks to allow to this hostgroup. forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall advanced: True multiline: True regex: ^(([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?)?$ @@ -73,14 +73,14 @@ firewall: tcp: &tcpsettings description: List of TCP ports for this port group. forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall advanced: True multiline: True duplicates: True udp: &udpsettings description: List of UDP ports for this port group. forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall advanced: True multiline: True duplicates: True @@ -206,7 +206,7 @@ firewall: advanced: True multiline: True forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall duplicates: True sensor: portgroups: *portgroupsdocker @@ -262,7 +262,7 @@ firewall: advanced: True multiline: True forcedType: "[]string" - helpLink: firewall.html + helpLink: firewall duplicates: True dockernet: portgroups: *portgroupshost diff --git a/salt/global/defaults.yaml b/salt/global/defaults.yaml index 5daa942c8..92b9c1c1a 100644 --- a/salt/global/defaults.yaml +++ b/salt/global/defaults.yaml @@ -1,3 +1,3 @@ global: - pcapengine: STENO + pcapengine: SURICATA pipeline: REDIS \ No newline at end of file diff --git a/salt/global/soc_global.yaml b/salt/global/soc_global.yaml index 047bb525b..33abbf690 100644 --- a/salt/global/soc_global.yaml +++ b/salt/global/soc_global.yaml @@ -18,13 +18,11 @@ global: regexFailureMessage: You must enter either ZEEK or SURICATA. global: True pcapengine: - description: Which engine to use for generating pcap. Options are STENO, SURICATA or TRANSITION. - regex: ^(STENO|SURICATA|TRANSITION)$ + description: Which engine to use for generating pcap. Currently only SURICATA is supported. + regex: ^(SURICATA)$ options: - - STENO - SURICATA - - TRANSITION - regexFailureMessage: You must enter either STENO, SURICATA or TRANSITION. + regexFailureMessage: You must enter either SURICATA. global: True ids: description: Which IDS engine to use. Currently only Suricata is supported. @@ -32,7 +30,7 @@ global: readonly: True advanced: True url_base: - description: Used for handling of authentication cookies. + description: The base URL for the Security Onion Console. Must be accessible by all nodes in the grid, as well as all analysts. Also used for handling of authentication cookies. Can be an IP address or a hostname/FQDN. Do not include protocol (http/https) or port number. global: True airgap: description: Airgapped systems do not have network connectivity to the internet. This setting represents how this grid was configured during initial setup. While it is technically possible to manually switch systems between airgap and non-airgap, there are some nuances and additional steps involved. For that reason this setting is marked read-only. Contact your support representative for guidance if there is a need to change this setting. diff --git a/salt/host/soc_host.yaml b/salt/host/soc_host.yaml index 8c790a8df..4d771a8d8 100644 --- a/salt/host/soc_host.yaml +++ b/salt/host/soc_host.yaml @@ -1,7 +1,7 @@ host: mainint: description: Main interface of the grid host. - helpLink: host.html + helpLink: ip-address mainip: description: Main IP address of the grid host. - helpLink: host.html \ No newline at end of file + helpLink: ip-address diff --git a/salt/hydra/enabled.sls b/salt/hydra/enabled.sls index e0f03e184..ee6a0c811 100644 --- a/salt/hydra/enabled.sls +++ b/salt/hydra/enabled.sls @@ -11,7 +11,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} {% if 'api' in salt['pillar.get']('features', []) %} @@ -26,32 +26,38 @@ so-hydra: - name: so-hydra - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-hydra'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-hydra'].ip }} - binds: - /opt/so/conf/hydra/:/hydra-conf:ro - /opt/so/log/hydra/:/hydra-log:rw - /nsm/hydra/db:/hydra-data:rw - {% if DOCKER.containers['so-hydra'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-hydra'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-hydra'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-hydra'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-hydra'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-hydra'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-hydra'].extra_hosts %} + {% if DOCKERMERGED.containers['so-hydra'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-hydra'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-hydra'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-hydra'].extra_env %} + {% if DOCKERMERGED.containers['so-hydra'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-hydra'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-hydra'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-hydra'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-hydra'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - restart_policy: unless-stopped - watch: - file: hydraconfig @@ -67,7 +73,7 @@ delete_so-hydra_so-status.disabled: wait_for_hydra: http.wait_for_successful_query: - - name: 'http://{{ GLOBALS.manager }}:4444/' + - name: 'http://{{ GLOBALS.manager }}:4444/health/alive' - ssl: True - verify_ssl: False - status: diff --git a/salt/hydra/soc_hydra.yaml b/salt/hydra/soc_hydra.yaml index 40e07ab1b..37613246b 100644 --- a/salt/hydra/soc_hydra.yaml +++ b/salt/hydra/soc_hydra.yaml @@ -1,7 +1,8 @@ hydra: enabled: - description: Enables or disables the API authentication system, used for service account authentication. Enabling this feature requires a valid Security Onion license key. Defaults to False. - helpLink: connect.html + description: Enables or disables the API authentication system, used for service account authentication. Enabling this feature requires a valid Security Onion license key. Defaults to False. + forcedType: bool + helpLink: connect-api global: True config: ttl: @@ -9,16 +10,16 @@ hydra: description: Amount of time that the generated access token will be valid. Specified in the form of 2h, which means 2 hours. global: True forcedType: string - helpLink: connect.html + helpLink: connect-api log: level: description: Log level to use for Kratos logs. global: True - helpLink: connect.html + helpLink: connect-api format: description: Log output format for Kratos logs. global: True - helpLink: connect.html + helpLink: connect-api secrets: system: description: Secrets used for token generation. Generated during installation. @@ -26,4 +27,4 @@ hydra: sensitive: True advanced: True forcedType: "[]string" - helpLink: connect.html + helpLink: connect-api diff --git a/salt/idh/enabled.sls b/salt/idh/enabled.sls index e08e6647f..295269126 100644 --- a/salt/idh/enabled.sls +++ b/salt/idh/enabled.sls @@ -6,7 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: - idh.config @@ -20,25 +20,31 @@ so-idh: - network_mode: host - binds: - /nsm/idh:/var/tmp:rw - - /opt/so/conf/idh/http-skins:/usr/local/lib/python3.12/site-packages/opencanary/modules/data/http/skin:ro + - /opt/so/conf/idh/http-skins:/opt/opencanary/http-skins:ro - /opt/so/conf/idh/opencanary.conf:/etc/opencanaryd/opencanary.conf:ro - {% if DOCKER.containers['so-idh'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-idh'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-idh'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-idh'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-idh'].extra_hosts %} + {% if DOCKERMERGED.containers['so-idh'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-idh'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-idh'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-idh'].extra_env %} + {% if DOCKERMERGED.containers['so-idh'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-idh'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-idh'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-idh'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-idh'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: opencanary_config - require: diff --git a/salt/idh/opencanary_config.map.jinja b/salt/idh/opencanary_config.map.jinja index 420cc7f79..ce7abedc6 100644 --- a/salt/idh/opencanary_config.map.jinja +++ b/salt/idh/opencanary_config.map.jinja @@ -28,6 +28,7 @@ {% set HTTPPROXYSKINLIST = OPENCANARYCONFIG.pop('httpproxy_x_skinlist') %} {% do OPENCANARYCONFIG.update({'http_x_skin_x_list': HTTPSKINLIST}) %} {% do OPENCANARYCONFIG.update({'httpproxy_x_skin_x_list': HTTPPROXYSKINLIST}) %} +{% do OPENCANARYCONFIG.update({'http_x_skindir': '/opt/opencanary/http-skins/' ~ OPENCANARYCONFIG['http_x_skin']}) %} {% set OPENSSH = salt['pillar.get']('idh:openssh', default=IDHCONFIG.idh.openssh, merge=True) %} diff --git a/salt/idh/openssh/config.sls b/salt/idh/openssh/config.sls index 5e2acd8d2..58fad40a2 100644 --- a/salt/idh/openssh/config.sls +++ b/salt/idh/openssh/config.sls @@ -3,7 +3,6 @@ include: - idh.openssh -{% if grains.os_family == 'RedHat' %} idh_sshd_selinux: selinux.port_policy_present: - port: {{ openssh_map.config.port }} @@ -13,7 +12,6 @@ idh_sshd_selinux: - file: openssh_config - require: - pkg: python_selinux_mgmt_tools -{% endif %} openssh_config: file.replace: diff --git a/salt/idh/openssh/init.sls b/salt/idh/openssh/init.sls index 79d082502..b530eb280 100644 --- a/salt/idh/openssh/init.sls +++ b/salt/idh/openssh/init.sls @@ -16,8 +16,6 @@ openssh: - name: {{ openssh_map.service }} {% endif %} -{% if grains.os_family == 'RedHat' %} python_selinux_mgmt_tools: pkg.installed: - name: policycoreutils-python-utils -{% endif %} diff --git a/salt/idh/skins/http/opencanary/basicLogin/redirect.html b/salt/idh/skins/http/opencanary/basicLogin/redirect.html new file mode 100644 index 000000000..1386b17f7 --- /dev/null +++ b/salt/idh/skins/http/opencanary/basicLogin/redirect.html @@ -0,0 +1,29 @@ + + + Redirect + + + +
+ +
+ + + diff --git a/salt/idh/skins/http/opencanary/nasLogin/redirect.html b/salt/idh/skins/http/opencanary/nasLogin/redirect.html new file mode 100644 index 000000000..1386b17f7 --- /dev/null +++ b/salt/idh/skins/http/opencanary/nasLogin/redirect.html @@ -0,0 +1,29 @@ + + + Redirect + + + +
+ +
+ + + diff --git a/salt/idh/soc_idh.yaml b/salt/idh/soc_idh.yaml index 0d8ccb393..7cda82390 100644 --- a/salt/idh/soc_idh.yaml +++ b/salt/idh/soc_idh.yaml @@ -1,7 +1,12 @@ idh: enabled: - description: Enables or disables the Intrusion Detection Honeypot (IDH) process. - helpLink: idh.html + description: Enables or disables the Intrusion Detection Honeypot (IDH) process. + forcedType: bool + helpLink: idh + restrict_management_ip: + description: Restricts management IP access to the IDH node. + forcedType: bool + helpLink: idh opencanary: config: logger: @@ -10,7 +15,7 @@ idh: readonly: True advanced: True global: True - helpLink: idh.html + helpLink: idh kwargs: formatters: plain: @@ -24,53 +29,54 @@ idh: filename: *loggingOptions portscan_x_enabled: &serviceOptions description: To enable this opencanary module, set this value to true. To disable set to false. This option only applies to IDH nodes within your grid. - helpLink: idh.html + forcedType: bool + helpLink: idh portscan_x_logfile: *loggingOptions portscan_x_synrate: description: Portscan - syn rate limiting advanced: True - helpLink: idh.html + helpLink: idh portscan_x_nmaposrate: description: Portscan - nmap OS rate limiting advanced: True - helpLink: idh.html + helpLink: idh portscan_x_lorate: description: Portscan - lo rate limiting advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_x_maxnum: description: Portscan - maxnum advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_x_enabled: *serviceOptions tcpbanner_1_x_enabled: *serviceOptions tcpbanner_1_x_port: &portOptions description: Port the service should listen on. advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_1_x_datareceivedbanner: &bannerOptions description: Data Received Banner advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_1_x_initbanner: *bannerOptions tcpbanner_1_x_alertstring_x_enabled: *serviceOptions tcpbanner_1_x_keep_alive_x_enabled: *serviceOptions tcpbanner_1_x_keep_alive_secret: description: Keep Alive Secret advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_1_x_keep_alive_probes: description: Keep Alive Probes advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_1_x_keep_alive_interval: description: Keep Alive Interval advanced: True - helpLink: idh.html + helpLink: idh tcpbanner_1_x_keep_alive_idle: description: Keep Alive Idle advanced: True - helpLink: idh.html + helpLink: idh ftp_x_enabled: *serviceOptions ftp_x_port: *portOptions ftp_x_banner: *bannerOptions @@ -82,11 +88,11 @@ idh: http_x_skin: &skinOptions description: HTTP skin advanced: True - helpLink: idh.html + helpLink: idh http_x_skinlist: &skinlistOptions description: List of skins to use for the service. advanced: True - helpLink: idh.html + helpLink: idh httpproxy_x_enabled: *serviceOptions httpproxy_x_port: *portOptions httpproxy_x_skin: *skinOptions @@ -95,7 +101,7 @@ idh: mssql_x_version: &versionOptions description: Specify the version the service should present. advanced: True - helpLink: idh.html + helpLink: idh mssql_x_port: *portOptions mysql_x_enabled: *serviceOptions mysql_x_port: *portOptions @@ -119,16 +125,17 @@ idh: telnet_x_honeycreds: description: Credentials list for the telnet service. advanced: True - helpLink: idh.html + helpLink: idh tftp_x_enabled: *serviceOptions tftp_x_port: *portOptions vnc_x_enabled: *serviceOptions vnc_x_port: *portOptions openssh: - enable: + enable: description: This is the real SSH service for the host machine. - helpLink: idh.html + forcedType: bool + helpLink: idh config: port: description: Port that the real SSH service will listen on and will only be accessible from the manager. - helpLink: idh.html + helpLink: idh diff --git a/salt/influxdb/config.sls b/salt/influxdb/config.sls index 0f315666a..bf8b67b78 100644 --- a/salt/influxdb/config.sls +++ b/salt/influxdb/config.sls @@ -9,7 +9,6 @@ include: - salt.minion - - ssl # Influx DB influxconfdir: diff --git a/salt/influxdb/enabled.sls b/salt/influxdb/enabled.sls index 293a917cb..45038ece5 100644 --- a/salt/influxdb/enabled.sls +++ b/salt/influxdb/enabled.sls @@ -6,11 +6,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% set PASSWORD = salt['pillar.get']('secrets:influx_pass') %} {% set TOKEN = salt['pillar.get']('influxdb:token') %} include: + - influxdb.ssl - influxdb.config - influxdb.sostatus @@ -20,7 +21,7 @@ so-influxdb: - hostname: influxdb - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-influxdb'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-influxdb'].ip }} - environment: - INFLUXD_CONFIG_PATH=/conf/config.yaml - INFLUXDB_HTTP_LOG_ENABLED=false @@ -30,8 +31,8 @@ so-influxdb: - DOCKER_INFLUXDB_INIT_ORG=Security Onion - DOCKER_INFLUXDB_INIT_BUCKET=telegraf/so_short_term - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN={{ TOKEN }} - {% if DOCKER.containers['so-influxdb'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-influxdb'].extra_env %} + {% if DOCKERMERGED.containers['so-influxdb'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-influxdb'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} @@ -42,23 +43,31 @@ so-influxdb: - /nsm/influxdb:/var/lib/influxdb2:rw - /etc/pki/influxdb.crt:/conf/influxdb.crt:ro - /etc/pki/influxdb.key:/conf/influxdb.key:ro - {% if DOCKER.containers['so-influxdb'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-influxdb'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-influxdb'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-influxdb'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-influxdb'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-influxdb'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-influxdb'].extra_hosts %} + {% if DOCKERMERGED.containers['so-influxdb'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-influxdb'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-influxdb'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-influxdb'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-influxdb'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: influxdbconf + - x509: influxdb_key + - x509: influxdb_crt - require: - file: influxdbconf - x509: influxdb_key diff --git a/salt/influxdb/soc_influxdb.yaml b/salt/influxdb/soc_influxdb.yaml index 846152cf3..3dbf0875b 100644 --- a/salt/influxdb/soc_influxdb.yaml +++ b/salt/influxdb/soc_influxdb.yaml @@ -1,358 +1,372 @@ influxdb: enabled: description: Enables the grid metrics collection storage system. Security Onion grid health monitoring requires this process to remain enabled. WARNING - Disabling the process is unsupported, and will cause unexpected results. - helpLink: influxdb.html + forcedType: bool + helpLink: influxdb config: assets-path: description: Path to the InfluxDB user interface assets located inside the so-influxdb container. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb bolt-path: description: Path to the bolt DB file located inside the so-influxdb container. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb engine-path: description: Path to the engine directory located inside the so-influxdb container. This directory stores the time series data. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb feature-flags: description: List of key=value flags to enable. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb flux-log-enabled: description: Controls whether detailed flux query logging is enabled. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb hardening-enabled: description: If true, enforces outbound connections from the InfluxDB process must never attempt to reach an internal, private network address. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb http-bind-address: description: The URL and port on which InfluxDB will listen for new connections. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb http-idle-timeout: description: Keep-alive timeout while a connection waits for new requests. A value of 0 is the same as no timeout enforced. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb http-read-header-timeout: description: The duration to wait for a request header before closing the connection. A value of 0 is the same as no timeout enforced. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb http-read-timeout: description: The duration to wait for the request to be fully read before closing the connection. A value of 0 is the same as no timeout enforced. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb http-write-timeout: description: The duration to wait for the response to be fully written before closing the connection. A value of 0 is the same as no timeout enforced. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb influxql-max-select-buckets: description: Maximum number of group-by clauses in a SELECT statement. A value of 0 is the same as unlimited. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb influxql-max-select-point: description: Maximum number of points that can be queried in a SELECT statement. A value of 0 is the same as unlimited. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb influxql-max-select-series: description: Maximum number of series that can be returned in a SELECT statement. A value of 0 is the same as unlimited. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb instance-id: description: Unique instance ID for this server, to avoid collisions in a replicated cluster. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb log-level: description: The log level to use for outputting log statements. Allowed values are debug, info, or error. global: True advanced: false regex: ^(info|debug|error)$ - helpLink: influxdb.html + helpLink: influxdb metrics-disabled: description: If true, the HTTP endpoint that exposes internal InfluxDB metrics will be inaccessible. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb no-tasks: description: If true, the task system will not process any queued tasks. Useful for troubleshooting startup problems. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb pprof-disabled: description: If true, the profiling data HTTP endpoint will be inaccessible. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb query-concurrency: description: Maximum number of queries to execute concurrently. A value of 0 is the same as unlimited. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb query-initial-memory-bytes: description: The initial number of bytes of memory to allocate for a new query. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb query-max-memory-bytes: description: The number of bytes of memory to allocate to all running queries. Should typically be the query bytes times the max concurrent queries. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb query-memory-bytes: description: Maximum number of bytes of memory to allocate to a query. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb query-queue-size: description: Maximum number of queries that can be queued at one time. If this value is reached, new queries will not be queued. A value of 0 is the same as unlimited. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb reporting-disabled: description: If true, prevents InfluxDB from sending telemetry updates to InfluxData's servers. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb secret-store: description: Determines the type of storage used for secrets. Allowed values are bolt or vault. global: True advanced: True regex: ^(bolt|vault)$ - helpLink: influxdb.html + helpLink: influxdb session-length: description: Number of minutes that a user login session can remain authenticated. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb session-renew-disabled: description: If true, user login sessions will renew after each request. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb sqlite-path: description: Path to the Sqlite3 database inside the container. This database stored user data and other information about the database. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-cache-max-memory-size: description: Maximum number of bytes to allocate to cache data per shard. If exceeded, new data writes will be rejected. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-cache-snapshot-memory-size: description: Number of bytes to allocate to cache snapshot data. When the cache reaches this size, it will be written to disk to increase available memory. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-cache-snapshot-write-cold-duration: description: Duration between snapshot writes to disk when the shard data hasn't been modified. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-compact-full-write-cold-duration: description: Duration between shard compactions when the shard data hasn't been modified. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-compact-throughput-burst: description: Maximum throughput (number of bytes per second) that compactions be written to disk. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-max-concurrent-compactions: description: Maximum number of concurrent compactions. A value of 0 is the same as half the available CPU processors (procs). global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-max-index-log-file-size: description: Maximum number of bytes of a write-ahead log (WAL) file before it will be compacted into an index on disk. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-no-validate-field-size: description: If true, incoming requests will skip the field size validation. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-retention-check-interval: description: Interval between reviewing each bucket's retention policy and the age of the associated data. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-series-file-max-concurrent-snapshot-compactions: description: Maximum number of concurrent snapshot compactions across all database partitions. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-series-id-set-cache-size: description: Maximum size of the series cache results. Higher values may increase performance for repeated data lookups. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-shard-precreator-advance-period: description: The duration before a successor shard group is created after the end-time has been reached. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-shard-precreator-check-interval: description: Interval between checking if new shards should be created. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-tsm-use-madv-willneed: description: If true, InfluxDB will manage TSM memory paging. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-validate-keys: description: If true, validates incoming requests for supported characters. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-wal-fsync-delay: description: Duration to wait before calling fsync. Useful for handling conflicts on slower disks. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-wal-max-concurrent-writes: description: Maximum number of concurrent write-ahead log (WAL) writes to disk. The value of 0 is the same as CPU processors (procs) x 2. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-wal-max-write-delay: description: Maximum duration to wait before writing the write-ahead log (WAL) to disk, when the concurrency limit has been exceeded. A value of 0 is the same as no timeout. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb storage-write-timeout: description: Maximum time to wait for a write-ahead log (WAL) to write to disk before aborting. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb store: description: The type of data store to use for HTTP resources. Allowed values are disk or memory. Memory should not be used for production Security Onion installations. global: True advanced: True regex: ^(disk|memory)$ - helpLink: influxdb.html + helpLink: influxdb tls-cert: description: The container path to the certificate to use for TLS encryption of the HTTP requests and responses. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb tls-key: description: The container path to the certificate key to use for TLS encryption of the HTTP requests and responses. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb tls-min-version: description: The minimum supported version of TLS to be enforced on all incoming HTTP requests. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb tls-strict-ciphers: description: If true, the allowed ciphers used with TLS connections are ECDHE_RSA_WITH_AES_256_GCM_SHA384, ECDHE_RSA_WITH_AES_256_CBC_SHA, RSA_WITH_AES_256_GCM_SHA384, or RSA_WITH_AES_256_CBC_SHA. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb tracing-type: description: The tracing format for debugging purposes. Allowed values are log or jaeger, or leave blank to disable tracing. global: True advanced: True - helpLink: influxdb.html - ui-disabled: + helpLink: influxdb + ui-disabled: description: If true, the InfluxDB HTTP user interface will be disabled. This will prevent use of the included InfluxDB dashboard visualizations. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-addr: description: Vault server address. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-cacert: description: Path to the Vault's single certificate authority certificate file within the container. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-capath: description: Path to the Vault's certificate authority directory within the container. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-client-cert: description: Vault client certificate path within the container. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-client-key: description: Vault client certificate key path within the container. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-client-timeout: description: Duration to wait for a response from the Vault server before aborting. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-max-retries: description: Maximum number of retries when attempting to contact the Vault server. A value of 0 is the same as disabling retries. global: True advanced: True - helpLink: influxdb.html - vault-skip-verify: + helpLink: influxdb + vault-skip-verify: description: Skip certification validation of the Vault server. + forcedType: bool global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-tls-server-name: description: SNI host to specify when using TLS to connect to the Vault server. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb vault-token: description: Vault token used for authentication. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb buckets: so_short_term: duration: description: Amount of time (in seconds) to keep short term data. global: True - helpLink: influxdb.html + helpLink: influxdb shard_duration: description: Amount of the time (in seconds) range covered by the shard group. global: True - helpLink: influxdb.html + helpLink: influxdb so_long_term: duration: description: Amount of time (in seconds) to keep long term downsampled data. global: True - helpLink: influxdb.html + helpLink: influxdb shard_duration: description: Amount of the time (in seconds) range covered by the shard group. global: True - helpLink: influxdb.html + helpLink: influxdb downsample: so_long_term: resolution: description: Amount of time to turn into a single data point. global: True - helpLink: influxdb.html + helpLink: influxdb diff --git a/salt/influxdb/ssl.sls b/salt/influxdb/ssl.sls new file mode 100644 index 000000000..930879c75 --- /dev/null +++ b/salt/influxdb/ssl.sls @@ -0,0 +1,55 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/map.jinja' import CA %} + +influxdb_key: + x509.private_key_managed: + - name: /etc/pki/influxdb.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/influxdb.key') -%} + - prereq: + - x509: /etc/pki/influxdb.crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +# Create a cert for the talking to influxdb +influxdb_crt: + x509.certificate_managed: + - name: /etc/pki/influxdb.crt + - ca_server: {{ CA.server }} + - signing_policy: influxdb + - private_key: /etc/pki/influxdb.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + +influxkeyperms: + file.managed: + - replace: False + - name: /etc/pki/influxdb.key + - mode: 640 + - group: 939 + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/influxdb/templates/alarm_steno_packet_loss.json b/salt/influxdb/templates/alarm_steno_packet_loss.json deleted file mode 100644 index c5cfb4297..000000000 --- a/salt/influxdb/templates/alarm_steno_packet_loss.json +++ /dev/null @@ -1,27 +0,0 @@ -[{ - "apiVersion": "influxdata.com/v2alpha1", - "kind": "CheckThreshold", - "metadata": { - "name": "steno-packet-loss" - }, - "spec": { - "description": "Triggers when the average percent of packet loss is above the defined threshold. To tune this alert, modify the value for the appropriate alert level.", - "every": "1m", - "name": "Stenographer Packet Loss", - "query": "from(bucket: \"telegraf/so_short_term\")\n |\u003e range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |\u003e filter(fn: (r) =\u003e r[\"_measurement\"] == \"stenodrop\")\n |\u003e filter(fn: (r) =\u003e r[\"_field\"] == \"drop\")\n |\u003e aggregateWindow(every: 1m, fn: mean, createEmpty: false)\n |\u003e yield(name: \"mean\")", - "status": "active", - "statusMessageTemplate": "Stenographer Packet Loss on node ${r.host} has reached the ${ r._level } threshold. The current packet loss is ${ r.drop }%.", - "thresholds": [ - { - "level": "CRIT", - "type": "greater", - "value": 5 - }, - { - "level": "WARN", - "type": "greater", - "value": 3 - } - ] - } -}] diff --git a/salt/influxdb/templates/dashboard-security_onion_performance.json b/salt/influxdb/templates/dashboard-security_onion_performance.json index 1e66b2b40..d4873fc03 100644 --- a/salt/influxdb/templates/dashboard-security_onion_performance.json +++ b/salt/influxdb/templates/dashboard-security_onion_performance.json @@ -1 +1 @@ -[{"apiVersion":"influxdata.com/v2alpha1","kind":"Dashboard","metadata":{"name":"vivid-wilson-002001"},"spec":{"charts":[{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Uptime","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime\")\n |> hostFilter()\n |> map(fn: (r) => ({r with _value: r._value / (24 * 60 * 60)}))\n |> group(columns: [\"host\"])\n |> last()\n |> lowestMin(n:1)"}],"staticLegend":{},"suffix":" days","width":1},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"},{"id":"z83MTSufTrlrCoEPiBXda","name":"ruby","type":"text","hex":"#BF3D5E","value":1}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Critical Alarms","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> filter(fn: (r) => r[\"_level\"] == \"crit\")\n |> count()"}],"staticLegend":{},"suffix":" ","width":1,"yPos":2},{"colors":[{"id":"base","name":"rainforest","type":"text","hex":"#4ED8A0"},{"id":"QCTYWuGuHkikYFsZSKMzQ","name":"rainforest","type":"text","hex":"#4ED8A0"},{"id":"QdpMyTRBb0LJ56-P5wfAW","name":"laser","type":"text","hex":"#00C9FF","value":1},{"id":"VQGwCoMrxZyP8asiOW5Cq","name":"tiger","type":"text","hex":"#F48D38","value":2},{"id":"zSO9QkesSIxrU_ntCBx2i","name":"ruby","type":"text","hex":"#BF3D5E","value":3}],"fieldOptions":[{"fieldName":"_time","visible":true},{"displayName":"Alarm","fieldName":"_check_name","visible":true},{"displayName":"Severity","fieldName":"_value","visible":true},{"displayName":"Status","fieldName":"_level","visible":true}],"height":6,"kind":"Table","name":"Alarm Status","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> drop(columns: [\"_value\"])\n |> duplicate(column: \"_level\", as: \"_value\")\n |> map(fn: (r) => ({ r with _value: if r._value == \"ok\" then 0 else if r._value == \"info\" then 1 else if r._value == \"warn\" then 2 else 3 }))\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> keep(columns: [\"_check_name\",\"_level\",\"_value\"])"}],"staticLegend":{},"tableOptions":{"sortBy":"_check_name","verticalTimeAxis":true},"timeFormat":"YYYY-MM-DD HH:mm:ss","width":3,"yPos":4},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"B"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Elasticsearch Storage Size","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"store_size_in_bytes\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"mean\")"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"store_size_in_bytes\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":10},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"B"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"InfluxDB Size","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"influxsize\")\n |> filter(fn: (r) => r[\"_field\"] == \"kbytes\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 1000.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"mean\")"},{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"influxsize\")\n |> filter(fn: (r) => r[\"_field\"] == \"kbytes\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 1000.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":14},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":" days"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"System Uptime","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24 * 60 * 60)}))\n |> yield(name: \"last\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24 * 60 * 60)}))\n |> yield(name: \"Trend\")"}],"shade":true,"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":18},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"lQ75rvTyd2Lq5pZjzy6LB","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"KLfpRZtiEnU2GxjPtrrzQ","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"1kLynwKxvJ3B5IeJnrBqp","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka EPS","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"controllerHosts = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> filter(fn: (r) => r[\"_value\"] == 1)\n |> keep(columns: [\"host\"])\n |> distinct(column: \"host\")\n |> map(fn: (r) => ({r with _value: r.host}))\n |> keep(columns: [\"_value\"])\n\ncontrollerHostNames = controllerHosts |> findColumn(fn: (key) => true, column: \"_value\")\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_topics\")\n |> filter(fn: (r) => r[\"_field\"] == \"MessagesInPerSec.Count\")\n |> filter(fn: (r) => not contains(value: r.host, set: controllerHostNames))\n |> derivative(unit: 1s, nonNegative: true)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"controllerHosts = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> filter(fn: (r) => r[\"_value\"] == 1)\n |> keep(columns: [\"host\"])\n |> distinct(column: \"host\")\n |> map(fn: (r) => ({r with _value: r.host}))\n |> keep(columns: [\"_value\"])\n\ncontrollerHostNames = controllerHosts |> findColumn(fn: (key) => true, column: \"_value\")\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_topics\")\n |> filter(fn: (r) => r[\"_field\"] == \"MessagesInPerSec.Count\")\n |> filter(fn: (r) => not contains(value: r.host, set: controllerHostNames))\n |> derivative(unit: 1s, nonNegative: true)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":22},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"System CPU Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: r._value * -1.0 + 100.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\",\"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: r._value * -1.0 + 100.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":26},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"QDwChKZWuQV0BaJcEeSam","name":"Atlantis","type":"scale","hex":"#74D495"},{"id":"ThD0WTqKHltQEVlq9mo6K","name":"Atlantis","type":"scale","hex":"#3F3FBA"},{"id":"FBHYZiwDLKyQK3eRfUD-0","name":"Atlantis","type":"scale","hex":"#FF4D9E"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"System Memory Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":30},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Monitor Interface Traffic - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"bytes_recv\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":34},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Management Interface Traffic - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"bytes_recv\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":6,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":38},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Stenographer Packet Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"stenodrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"stenodrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":42},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Disk Usage /","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":46},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"5m Load Average","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"load5\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"width":1,"xPos":1},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"},{"id":"z83MTSufTrlrCoEPiBXda","name":"tiger","type":"text","hex":"#F48D38","value":1}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Warning Alarms","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> filter(fn: (r) => r[\"_level\"] == \"warn\")\n |> count()"}],"staticLegend":{},"suffix":" ","width":1,"xPos":1,"yPos":2},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"IO Wait","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_iowait\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":2},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"},{"id":"z83MTSufTrlrCoEPiBXda","name":"laser","type":"text","hex":"#00C9FF","value":1}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Informative Alarms","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> filter(fn: (r) => r[\"_level\"] == \"info\")\n |> count()"}],"staticLegend":{},"suffix":" ","width":1,"xPos":2,"yPos":2},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Estimated EPS In","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"in\")\n |> hostFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"width":1,"xPos":3},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"pineapple","type":"threshold","hex":"#FFB94A","value":70},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"fire","type":"threshold","hex":"#DC4E58","value":80},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"CPU Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> map(fn: (r) => ({r with _value: r._value * -1.0 + 100.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":3,"yPos":2},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"kOQLOg2H4FVEE-E1_L8Kq","name":"laser","type":"threshold","hex":"#00C9FF","value":85},{"id":"5IArg2lDb8KvnphywgUXa","name":"tiger","type":"threshold","hex":"#F48D38","value":90},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"ruby","type":"threshold","hex":"#BF3D5E","value":95},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"Root Disk Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"path\"] == \"/\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":3,"yPos":6},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Suricata Packet Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"suridrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"suridrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","xPos":3,"yCol":"_value","yPos":42},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Redis Queue","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"redisqueue\")\n |> filter(fn: (r) => r[\"_field\"] == \"unparsed\")\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"width":1,"xPos":4},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Elasticsearch Document Count","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"docs_count\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"mean\")"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"docs_count\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":10},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"heightRatio":0.301556420233463,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Redis Queue","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"redisqueue\")\n |> filter(fn: (r) => r[\"_field\"] == \"unparsed\")\n |> group(columns: [\"host\", \"_field\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"redisqueue\")\n |> filter(fn: (r) => r[\"_field\"] == \"unparsed\")\n |> group(columns: [\"host\", \"_field\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.301556420233463,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":14},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":" days"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container Uptime","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_status\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime_ns\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> group(columns: [\"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24 * 60 * 60 * 1000000000)}))\n |> yield(name: \"last\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_status\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime_ns\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> group(columns: [\"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24.0 * 60.0 * 60.0 * 1000000000.0)}))\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":18},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"hoverDimension":"auto","kind":"Single_Stat_Plus_Line","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka Active Controllers","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"current\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":22},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"hoverDimension":"auto","kind":"Single_Stat_Plus_Line","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka Active Brokers","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveBrokerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"trend\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveBrokerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"current\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":24},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"yT5vTIlaaFChSrQvKLfqf","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"mzzUVSu3ibTph1JmQmDAQ","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"mOcnDo7l8ii6qNLFIB5rs","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container CPU Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"mean\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":26},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"QDwChKZWuQV0BaJcEeSam","name":"Atlantis","type":"scale","hex":"#74D495"},{"id":"ThD0WTqKHltQEVlq9mo6K","name":"Atlantis","type":"scale","hex":"#3F3FBA"},{"id":"FBHYZiwDLKyQK3eRfUD-0","name":"Atlantis","type":"scale","hex":"#FF4D9E"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container Memory Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"mean\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":30},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b"}],"colorizeRows":true,"colors":[{"id":"0ynR6Zs0wuQ3WY0Lz-_KC","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"YiArehCNBwFm9mn8DSXSG","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"DxByY_EQW9Xs2jD5ktkG5","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container Traffic - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_net\")\n |> filter(fn: (r) => r[\"_field\"] == \"rx_bytes\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"mean\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_net\")\n |> filter(fn: (r) => r[\"_field\"] == \"rx_bytes\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with _value: r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":34},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Disk Usage /nsm","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/nsm\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/nsm\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xPos":4,"yPos":46},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Inbound Traffic","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\") \n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: r._value * 8.0 / (1000.0 * 1000.0)}))\n |> group(columns: [\"host\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> last()\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":" Mb/s","width":1,"xPos":5},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Inbound Drops","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop_in\") \n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: r._value * 8.0 / (1000.0 * 1000.0)}))\n |> group(columns: [\"host\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> last()\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":" Mb/s","width":1,"xPos":6},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"pineapple","type":"threshold","hex":"#FFB94A","value":70},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"fire","type":"threshold","hex":"#DC4E58","value":80},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"Memory Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":6,"yPos":2},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"laser","type":"threshold","hex":"#00C9FF","value":85},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"tiger","type":"threshold","hex":"#F48D38","value":90},{"id":"H7uprvKmMEh39en6X-ms_","name":"ruby","type":"threshold","hex":"#BF3D5E","value":95},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"NSM Disk Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"path\"] == \"/nsm\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":6,"yPos":6},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Management Interface Traffic - Outbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_sent\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n \n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"bytes_sent\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_sent\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n \n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":6,"widthRatio":1,"xCol":"_time","xPos":6,"yCol":"_value","yPos":38},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Zeek Packet Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekdrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekdrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","xPos":6,"yCol":"_value","yPos":42},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Capture Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekcaptureloss\")\n |> filter(fn: (r) => r[\"_field\"] == \"loss\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":7},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Zeek Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekdrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":8},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"s"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"heightRatio":0.301556420233463,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Elastic Ingest Time Spent","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_community_id_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"community.id_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_conditional_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"conditional_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_date_index_name_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"date.index.name_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_date_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"date_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_dissect_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"dissect_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_dot_expander_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"dot.expander_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_geoip_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"geoip_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_grok_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"grok_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_json_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"json_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_kv_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"kv_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_lowercase_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"lowercase_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_rename_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"rename_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_script_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"script_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_user_agent_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"user.agent_time\")"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.301556420233463,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":10},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"1m Load Average","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"load1\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"load1\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\",\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":14,"yTickStep":1},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":" e/s"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"heightRatio":0.301556420233463,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Logstash EPS","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"in\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"out\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: -r._value}))\n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"in\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"out\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: -r._value}))\n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.301556420233463,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":18},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":4,"hoverDimension":"auto","kind":"Single_Stat_Plus_Line","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka Under Replicated Partitions","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_partition\")\n |> filter(fn: (r) => r[\"_field\"] == \"UnderReplicatedPartitions\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"partition\",\"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_partition\")\n |> filter(fn: (r) => r[\"_field\"] == \"UnderReplicatedPartitions\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"partition\",\"host\", \"role\"])\n |> yield(name: \"trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":22},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"UAehjIsi65P8u92M_3sQY","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"_SCP8Npp4NVMx2N4mfuzX","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"BoMPg4R1KDp_UsRORdV3_","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"IO Wait","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_iowait\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_iowait\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":26},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"QDwChKZWuQV0BaJcEeSam","name":"Atlantis","type":"scale","hex":"#74D495"},{"id":"ThD0WTqKHltQEVlq9mo6K","name":"Atlantis","type":"scale","hex":"#3F3FBA"},{"id":"FBHYZiwDLKyQK3eRfUD-0","name":"Atlantis","type":"scale","hex":"#FF4D9E"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Swap Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"swap\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"swap\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":30},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Monitor Interface Drops - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop_in\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"drop_in\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop_in\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":34},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":" days"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Stenographer PCAP Retention","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"pcapage\")\n |> filter(fn: (r) => r[\"_field\"] == \"seconds\")\n |> map(fn: (r) => ({ r with _value: r._value / (24.0 * 3600.0)}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])"},{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"pcapage\")\n |> filter(fn: (r) => r[\"_field\"] == \"seconds\")\n |> map(fn: (r) => ({ r with _value: r._value / (24.0 * 3600.0)}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":46},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Suricata Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"suridrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":9},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"pineapple","type":"threshold","hex":"#FFB94A","value":50},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"fire","type":"threshold","hex":"#DC4E58","value":70},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"Swap Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"swap\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":9,"yPos":2},{"colors":[{"id":"base","name":"white","type":"text","hex":"#ffffff"}],"fieldOptions":[{"displayName":"Host","fieldName":"host","visible":true},{"displayName":"Name","fieldName":"container_name","visible":true},{"displayName":"Status","fieldName":"container_status","visible":true},{"displayName":"OOM Killed","fieldName":"_value","visible":true},{"displayName":"_start","fieldName":"_start","visible":true},{"displayName":"_stop","fieldName":"_stop","visible":true},{"displayName":"_time","fieldName":"_time","visible":true},{"displayName":"_field","fieldName":"_field","visible":true},{"displayName":"_measurement","fieldName":"_measurement","visible":true},{"displayName":"engine_host","fieldName":"engine_host","visible":true},{"displayName":"role","fieldName":"role","visible":true},{"displayName":"server_version","fieldName":"server_version","visible":true},{"displayName":"container_image","fieldName":"container_image","visible":true},{"displayName":"container_version","fieldName":"container_version","visible":true},{"displayName":"description","fieldName":"description","visible":true},{"displayName":"maintainer","fieldName":"maintainer","visible":true},{"displayName":"io.k8s.description","fieldName":"io.k8s.description","visible":true},{"displayName":"io.k8s.display-name","fieldName":"io.k8s.display-name","visible":true},{"displayName":"license","fieldName":"license","visible":true},{"displayName":"name","fieldName":"name","visible":true},{"displayName":"org.label-schema.build-date","fieldName":"org.label-schema.build-date","visible":true},{"displayName":"org.label-schema.license","fieldName":"org.label-schema.license","visible":true},{"displayName":"org.label-schema.name","fieldName":"org.label-schema.name","visible":true},{"displayName":"org.label-schema.schema-version","fieldName":"org.label-schema.schema-version","visible":true},{"displayName":"org.label-schema.url","fieldName":"org.label-schema.url","visible":true},{"displayName":"org.label-schema.vcs-ref","fieldName":"org.label-schema.vcs-ref","visible":true},{"displayName":"org.label-schema.vcs-url","fieldName":"org.label-schema.vcs-url","visible":true},{"displayName":"org.label-schema.vendor","fieldName":"org.label-schema.vendor","visible":true},{"displayName":"org.label-schema.version","fieldName":"org.label-schema.version","visible":true},{"displayName":"org.opencontainers.image.created","fieldName":"org.opencontainers.image.created","visible":true},{"displayName":"org.opencontainers.image.licenses","fieldName":"org.opencontainers.image.licenses","visible":true},{"displayName":"org.opencontainers.image.title","fieldName":"org.opencontainers.image.title","visible":true},{"displayName":"org.opencontainers.image.vendor","fieldName":"org.opencontainers.image.vendor","visible":true},{"displayName":"release","fieldName":"release","visible":true},{"displayName":"summary","fieldName":"summary","visible":true},{"displayName":"url","fieldName":"url","visible":true},{"displayName":"vendor","fieldName":"vendor","visible":true},{"displayName":"version","fieldName":"version","visible":true},{"displayName":"org.label-schema.usage","fieldName":"org.label-schema.usage","visible":true},{"displayName":"org.opencontainers.image.documentation","fieldName":"org.opencontainers.image.documentation","visible":true},{"displayName":"org.opencontainers.image.revision","fieldName":"org.opencontainers.image.revision","visible":true},{"displayName":"org.opencontainers.image.source","fieldName":"org.opencontainers.image.source","visible":true},{"displayName":"org.opencontainers.image.url","fieldName":"org.opencontainers.image.url","visible":true},{"displayName":"org.opencontainers.image.version","fieldName":"org.opencontainers.image.version","visible":true},{"displayName":"org.opencontainers.image.description","fieldName":"org.opencontainers.image.description","visible":true}],"height":4,"kind":"Table","name":"Most Recent Container Events","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_status\")\n |> filter(fn: (r) => r[\"_field\"] == \"oomkilled\")\n |> filter(fn: (r) => r[\"container_status\"] != \"running\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"container_name\", \"host\"])\n |> last()\n |> group()\n |> keep(columns: [\"_value\", \"container_name\", \"host\", \"container_status\"])"}],"staticLegend":{},"tableOptions":{"sortBy":"container_name","verticalTimeAxis":true},"timeFormat":"YYYY-MM-DD HH:mm:ss","width":3,"xPos":9,"yPos":6},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Zeek Capture Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekcaptureloss\")\n |> filter(fn: (r) => r[\"_field\"] == \"loss\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekcaptureloss\")\n |> filter(fn: (r) => r[\"_field\"] == \"loss\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","xPos":9,"yCol":"_value","yPos":42},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Stenographer Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"stenodrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":10},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"PCAP Retention","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"pcapage\")\n |> filter(fn: (r) => r[\"_field\"] == \"seconds\")\n |> hostFilter()\n |> map(fn: (r) => ({r with _value: r._value / (24.0 * 60.0 * 60.0)}))\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":" days","width":1,"xPos":11}],"description":"Visualize the Security Onion grid performance metrics and alarm statuses.","name":"Security Onion Performance"}}] \ No newline at end of file +[{"apiVersion":"influxdata.com/v2alpha1","kind":"Dashboard","metadata":{"name":"vivid-wilson-002001"},"spec":{"charts":[{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Uptime","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime\")\n |> hostFilter()\n |> map(fn: (r) => ({r with _value: r._value / (24 * 60 * 60)}))\n |> group(columns: [\"host\"])\n |> last()\n |> lowestMin(n:1)"}],"staticLegend":{},"suffix":" days","width":1},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"},{"id":"z83MTSufTrlrCoEPiBXda","name":"ruby","type":"text","hex":"#BF3D5E","value":1}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Critical Alarms","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> filter(fn: (r) => r[\"_level\"] == \"crit\")\n |> count()"}],"staticLegend":{},"suffix":" ","width":1,"yPos":2},{"colors":[{"id":"base","name":"rainforest","type":"text","hex":"#4ED8A0"},{"id":"QCTYWuGuHkikYFsZSKMzQ","name":"rainforest","type":"text","hex":"#4ED8A0"},{"id":"QdpMyTRBb0LJ56-P5wfAW","name":"laser","type":"text","hex":"#00C9FF","value":1},{"id":"VQGwCoMrxZyP8asiOW5Cq","name":"tiger","type":"text","hex":"#F48D38","value":2},{"id":"zSO9QkesSIxrU_ntCBx2i","name":"ruby","type":"text","hex":"#BF3D5E","value":3}],"fieldOptions":[{"fieldName":"_time","visible":true},{"displayName":"Alarm","fieldName":"_check_name","visible":true},{"displayName":"Severity","fieldName":"_value","visible":true},{"displayName":"Status","fieldName":"_level","visible":true}],"height":6,"kind":"Table","name":"Alarm Status","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> drop(columns: [\"_value\"])\n |> duplicate(column: \"_level\", as: \"_value\")\n |> map(fn: (r) => ({ r with _value: if r._value == \"ok\" then 0 else if r._value == \"info\" then 1 else if r._value == \"warn\" then 2 else 3 }))\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> keep(columns: [\"_check_name\",\"_level\",\"_value\"])"}],"staticLegend":{},"tableOptions":{"sortBy":"_check_name","verticalTimeAxis":true},"timeFormat":"YYYY-MM-DD HH:mm:ss","width":3,"yPos":4},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"B"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Elasticsearch Storage Size","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"store_size_in_bytes\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"mean\")"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"store_size_in_bytes\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":10},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"B"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"InfluxDB Size","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"influxsize\")\n |> filter(fn: (r) => r[\"_field\"] == \"kbytes\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 1000.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"mean\")"},{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"influxsize\")\n |> filter(fn: (r) => r[\"_field\"] == \"kbytes\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 1000.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":14},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":" days"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"System Uptime","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24 * 60 * 60)}))\n |> yield(name: \"last\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24 * 60 * 60)}))\n |> yield(name: \"Trend\")"}],"shade":true,"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":18},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"lQ75rvTyd2Lq5pZjzy6LB","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"KLfpRZtiEnU2GxjPtrrzQ","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"1kLynwKxvJ3B5IeJnrBqp","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka EPS","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"controllerHosts = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> filter(fn: (r) => r[\"_value\"] == 1)\n |> keep(columns: [\"host\"])\n |> distinct(column: \"host\")\n |> map(fn: (r) => ({r with _value: r.host}))\n |> keep(columns: [\"_value\"])\n\ncontrollerHostNames = controllerHosts |> findColumn(fn: (key) => true, column: \"_value\")\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_topics\")\n |> filter(fn: (r) => r[\"_field\"] == \"MessagesInPerSec.Count\")\n |> filter(fn: (r) => not contains(value: r.host, set: controllerHostNames))\n |> derivative(unit: 1s, nonNegative: true)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"controllerHosts = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> filter(fn: (r) => r[\"_value\"] == 1)\n |> keep(columns: [\"host\"])\n |> distinct(column: \"host\")\n |> map(fn: (r) => ({r with _value: r.host}))\n |> keep(columns: [\"_value\"])\n\ncontrollerHostNames = controllerHosts |> findColumn(fn: (key) => true, column: \"_value\")\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_topics\")\n |> filter(fn: (r) => r[\"_field\"] == \"MessagesInPerSec.Count\")\n |> filter(fn: (r) => not contains(value: r.host, set: controllerHostNames))\n |> derivative(unit: 1s, nonNegative: true)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":22},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"System CPU Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: r._value * -1.0 + 100.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\",\"host\", \"role\"])\n |> map(fn: (r) => ({r with _value: r._value * -1.0 + 100.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":26},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"QDwChKZWuQV0BaJcEeSam","name":"Atlantis","type":"scale","hex":"#74D495"},{"id":"ThD0WTqKHltQEVlq9mo6K","name":"Atlantis","type":"scale","hex":"#3F3FBA"},{"id":"FBHYZiwDLKyQK3eRfUD-0","name":"Atlantis","type":"scale","hex":"#FF4D9E"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"System Memory Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":30},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Monitor Interface Traffic - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"bytes_recv\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":34},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Management Interface Traffic - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"bytes_recv\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":6,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":38},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Disk Usage /","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","yCol":"_value","yPos":46},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"5m Load Average","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"load5\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"width":1,"xPos":1},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"},{"id":"z83MTSufTrlrCoEPiBXda","name":"tiger","type":"text","hex":"#F48D38","value":1}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Warning Alarms","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> filter(fn: (r) => r[\"_level\"] == \"warn\")\n |> count()"}],"staticLegend":{},"suffix":" ","width":1,"xPos":1,"yPos":2},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"IO Wait","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_iowait\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":2},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"},{"id":"z83MTSufTrlrCoEPiBXda","name":"laser","type":"text","hex":"#00C9FF","value":1}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Informative Alarms","queries":[{"query":"from(bucket: \"_monitoring\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"statuses\")\n |> filter(fn: (r) => r[\"_field\"] == \"_message\")\n |> group(columns: [\"_check_id\"])\n |> sort(columns: [\"_time\"])\n |> last()\n |> group()\n |> filter(fn: (r) => r[\"_level\"] == \"info\")\n |> count()"}],"staticLegend":{},"suffix":" ","width":1,"xPos":2,"yPos":2},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Estimated EPS In","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"in\")\n |> hostFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"width":1,"xPos":3},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"pineapple","type":"threshold","hex":"#FFB94A","value":70},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"fire","type":"threshold","hex":"#DC4E58","value":80},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"CPU Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_idle\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> map(fn: (r) => ({r with _value: r._value * -1.0 + 100.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":3,"yPos":2},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"kOQLOg2H4FVEE-E1_L8Kq","name":"laser","type":"threshold","hex":"#00C9FF","value":85},{"id":"5IArg2lDb8KvnphywgUXa","name":"tiger","type":"threshold","hex":"#F48D38","value":90},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"ruby","type":"threshold","hex":"#BF3D5E","value":95},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"Root Disk Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"path\"] == \"/\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":3,"yPos":6},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Suricata Packet Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"suridrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"suridrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","xPos":3,"yCol":"_value","yPos":42},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"kind":"Single_Stat","name":"Redis Queue","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"redisqueue\")\n |> filter(fn: (r) => r[\"_field\"] == \"unparsed\")\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"width":1,"xPos":4},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Elasticsearch Document Count","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"docs_count\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"mean\")"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_indices\")\n |> filter(fn: (r) => r[\"_field\"] == \"docs_count\")\n |> filter(fn: (r) => r[\"host\"] == r[\"node_name\"])\n |> hostFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":10},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"heightRatio":0.301556420233463,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Redis Queue","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"redisqueue\")\n |> filter(fn: (r) => r[\"_field\"] == \"unparsed\")\n |> group(columns: [\"host\", \"_field\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"redisqueue\")\n |> filter(fn: (r) => r[\"_field\"] == \"unparsed\")\n |> group(columns: [\"host\", \"_field\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.301556420233463,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":14},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":" days"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container Uptime","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_status\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime_ns\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> group(columns: [\"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24 * 60 * 60 * 1000000000)}))\n |> yield(name: \"last\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_status\")\n |> filter(fn: (r) => r[\"_field\"] == \"uptime_ns\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> group(columns: [\"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> map(fn: (r) => ({r with _value: float(v: r._value) / float(v: 24.0 * 60.0 * 60.0 * 1000000000.0)}))\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":18},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"hoverDimension":"auto","kind":"Single_Stat_Plus_Line","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka Active Controllers","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"current\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveControllerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":22},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":2,"hoverDimension":"auto","kind":"Single_Stat_Plus_Line","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka Active Brokers","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveBrokerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"trend\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_controller\")\n |> filter(fn: (r) => r[\"_field\"] == \"ActiveBrokerCount.Value\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"current\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":24},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"yT5vTIlaaFChSrQvKLfqf","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"mzzUVSu3ibTph1JmQmDAQ","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"mOcnDo7l8ii6qNLFIB5rs","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container CPU Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"mean\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_cpu\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":26},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"QDwChKZWuQV0BaJcEeSam","name":"Atlantis","type":"scale","hex":"#74D495"},{"id":"ThD0WTqKHltQEVlq9mo6K","name":"Atlantis","type":"scale","hex":"#3F3FBA"},{"id":"FBHYZiwDLKyQK3eRfUD-0","name":"Atlantis","type":"scale","hex":"#FF4D9E"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container Memory Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"mean\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_percent\")\n |> filter(fn: (r) => r[\"container_status\"] == \"running\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":30},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b"}],"colorizeRows":true,"colors":[{"id":"0ynR6Zs0wuQ3WY0Lz-_KC","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"YiArehCNBwFm9mn8DSXSG","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"DxByY_EQW9Xs2jD5ktkG5","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Container Traffic - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_net\")\n |> filter(fn: (r) => r[\"_field\"] == \"rx_bytes\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"mean\")"},{"query":"containerFilter = (tables=<-) =>\n if v.Container != \"(All)\" then\n tables |> filter(fn: (r) => r[\"container_name\"] == v.Container)\n else\n tables\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_net\")\n |> filter(fn: (r) => r[\"_field\"] == \"rx_bytes\")\n |> hostFilter()\n |> roleFilter()\n |> containerFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with _value: r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\", \"container_name\"])\n |> sort(columns: [\"_time\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":4,"yCol":"_value","yPos":34},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Disk Usage /nsm","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/nsm\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> filter(fn: (r) => r[\"path\"] == \"/nsm\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xPos":4,"yPos":46},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Inbound Traffic","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_recv\") \n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: r._value * 8.0 / (1000.0 * 1000.0)}))\n |> group(columns: [\"host\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> last()\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":" Mb/s","width":1,"xPos":5},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Inbound Drops","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop_in\") \n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: r._value * 8.0 / (1000.0 * 1000.0)}))\n |> group(columns: [\"host\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> last()\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":" Mb/s","width":1,"xPos":6},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"pineapple","type":"threshold","hex":"#FFB94A","value":70},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"fire","type":"threshold","hex":"#DC4E58","value":80},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"Memory Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"mem\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":6,"yPos":2},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"laser","type":"threshold","hex":"#00C9FF","value":85},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"tiger","type":"threshold","hex":"#F48D38","value":90},{"id":"H7uprvKmMEh39en6X-ms_","name":"ruby","type":"threshold","hex":"#BF3D5E","value":95},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"NSM Disk Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"disk\")\n |> filter(fn: (r) => r[\"path\"] == \"/nsm\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":6,"yPos":6},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Management Interface Traffic - Outbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_sent\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n \n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"bytes_sent\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"manint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"bytes_sent\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n \n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":6,"widthRatio":1,"xCol":"_time","xPos":6,"yCol":"_value","yPos":38},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Zeek Packet Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekdrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekdrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> hostFilter()\n |> roleFilter()\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","xPos":6,"yCol":"_value","yPos":42},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Capture Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekcaptureloss\")\n |> filter(fn: (r) => r[\"_field\"] == \"loss\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":7},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Zeek Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekdrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":8},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"s"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"heightRatio":0.301556420233463,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Elastic Ingest Time Spent","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_community_id_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"community.id_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_conditional_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"conditional_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_date_index_name_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"date.index.name_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_date_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"date_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_dissect_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"dissect_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_dot_expander_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"dot.expander_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_geoip_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"geoip_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_grok_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"grok_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_json_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"json_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_kv_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"kv_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_lowercase_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"lowercase_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_rename_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"rename_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_script_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"script_time\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"elasticsearch_clusterstats_nodes\")\n |> filter(fn: (r) => r.role == \"standalone\" or r.role == \"eval\" or r.role == \"import\" or r.role == \"manager\" or r.role == \"managersearch\" or r.role == \"search\" or r.role == \"node\" or r.role == \"heavynode\")\n |> filter(fn: (r) => r[\"_field\"] == \"ingest_processor_stats_user_agent_time_in_millis\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"user.agent_time\")"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.301556420233463,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":10},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"sW2GqpGAsGB5Adx16jKjp","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"TsdXuXwdI5Npi9S8L4f-i","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"OGL29-SUbJ6FyQb0JzbaD","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"1m Load Average","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"load1\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"system\")\n |> filter(fn: (r) => r[\"_field\"] == \"load1\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\",\"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: true)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":14,"yTickStep":1},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":" e/s"}],"colorizeRows":true,"colors":[{"id":"xflqbsX-j3iq4ry5QOntK","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#8F8AF4"},{"id":"5H28HcITm6QVfQsXon0vq","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#A51414"},{"id":"25MrINwurNBkQqeKCkMPg","name":"Do Androids Dream of Electric Sheep?","type":"scale","hex":"#F4CF31"}],"geom":"line","height":4,"heightRatio":0.301556420233463,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Logstash EPS","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"in\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"out\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: -r._value}))\n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"in\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"logstash_events\")\n |> filter(fn: (r) => r[\"_field\"] == \"out\")\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\") \n |> map(fn: (r) => ({r with _value: -r._value}))\n |> group(columns: [\"_field\", \"host\", \"pipeline\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.301556420233463,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":18},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear"}],"colorizeRows":true,"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":0,"height":4,"hoverDimension":"auto","kind":"Single_Stat_Plus_Line","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Kafka Under Replicated Partitions","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_partition\")\n |> filter(fn: (r) => r[\"_field\"] == \"UnderReplicatedPartitions\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"partition\",\"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"kafka_partition\")\n |> filter(fn: (r) => r[\"_field\"] == \"UnderReplicatedPartitions\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"partition\",\"host\", \"role\"])\n |> yield(name: \"trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":22},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"UAehjIsi65P8u92M_3sQY","name":"Nineteen Eighty Four","type":"scale","hex":"#31C0F6"},{"id":"_SCP8Npp4NVMx2N4mfuzX","name":"Nineteen Eighty Four","type":"scale","hex":"#A500A5"},{"id":"BoMPg4R1KDp_UsRORdV3_","name":"Nineteen Eighty Four","type":"scale","hex":"#FF7E27"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"IO Wait","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_iowait\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"cpu\")\n |> filter(fn: (r) => r[\"cpu\"] == \"cpu-total\")\n |> filter(fn: (r) => r[\"_field\"] == \"usage_iowait\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":26},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"QDwChKZWuQV0BaJcEeSam","name":"Atlantis","type":"scale","hex":"#74D495"},{"id":"ThD0WTqKHltQEVlq9mo6K","name":"Atlantis","type":"scale","hex":"#3F3FBA"},{"id":"FBHYZiwDLKyQK3eRfUD-0","name":"Atlantis","type":"scale","hex":"#FF4D9E"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Swap Usage","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"swap\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"swap\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> roleFilter()\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":30},{"axes":[{"base":"10","name":"x","scale":"linear"},{"base":"10","name":"y","scale":"linear","suffix":"b/s"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"heightRatio":0.18482490272373542,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Monitor Interface Drops - Inbound","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop_in\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"drop_in\"}))"},{"query":"import \"join\"\n\nhostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nmanints = from(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"node_config\")\n |> hostFilter()\n |> filter(fn: (r) => r[\"_field\"] == \"monint\")\n |> distinct()\n |> group(columns: [\"host\"])\n\ntraffic = from(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"net\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop_in\")\n |> hostFilter()\n |> roleFilter()\n |> derivative(unit: 1s, nonNegative: true, columns: [\"_value\"], timeColumn: \"_time\")\n |> map(fn: (r) => ({r with \"_value\": r._value * 8.0}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"host\"])\n\njoin.inner(left: traffic, right: manints,\n on: (l,r) => l.interface == r._value,\n as: (l, r) => ({l with _value: l._value, result: \"Trend\"}))"}],"staticLegend":{"colorizeRows":true,"heightRatio":0.18482490272373542,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":34},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":" days"}],"colorizeRows":true,"colors":[{"id":"3PVw3hQuZUzyar7Js3mMH","name":"Ectoplasm","type":"scale","hex":"#DA6FF1"},{"id":"O34ux-D8Xq_1-eeWRyYYH","name":"Ectoplasm","type":"scale","hex":"#00717A"},{"id":"P04RoKOHBdLdvfrfFbn0F","name":"Ectoplasm","type":"scale","hex":"#ACFF76"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"PCAP Retention","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"pcapage\")\n |> filter(fn: (r) => r[\"_field\"] == \"seconds\")\n |> map(fn: (r) => ({ r with _value: r._value / (24.0 * 3600.0)}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])"},{"query":"import \"join\"\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"pcapage\")\n |> filter(fn: (r) => r[\"_field\"] == \"seconds\")\n |> map(fn: (r) => ({ r with _value: r._value / (24.0 * 3600.0)}))\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> group(columns: [\"_field\",\"host\"])\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":4,"widthRatio":1,"xCol":"_time","xPos":8,"yCol":"_value","yPos":46},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"Suricata Loss","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"suridrop\")\n |> filter(fn: (r) => r[\"_field\"] == \"drop\")\n |> map(fn: (r) => ({r with _value: r._value * 100.0}))\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> aggregateWindow(every: v.windowPeriod, fn: mean)\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":"%","width":1,"xPos":9},{"colors":[{"id":"0","name":"viridian","type":"min","hex":"#32B08C"},{"id":"5IArg2lDb8KvnphywgUXa","name":"pineapple","type":"threshold","hex":"#FFB94A","value":50},{"id":"yFhH3mtavjuAZh6cEt5lx","name":"fire","type":"threshold","hex":"#DC4E58","value":70},{"id":"1","name":"ruby","type":"max","hex":"#BF3D5E","value":100}],"decimalPlaces":0,"height":4,"kind":"Gauge","name":"Swap Usage","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"swap\")\n |> filter(fn: (r) => r[\"_field\"] == \"used_percent\")\n |> hostFilter()\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n: 1)\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"}],"staticLegend":{},"suffix":"%","tickSuffix":"%","width":3,"xPos":9,"yPos":2},{"colors":[{"id":"base","name":"white","type":"text","hex":"#ffffff"}],"fieldOptions":[{"displayName":"Host","fieldName":"host","visible":true},{"displayName":"Name","fieldName":"container_name","visible":true},{"displayName":"Status","fieldName":"container_status","visible":true},{"displayName":"OOM Killed","fieldName":"_value","visible":true},{"displayName":"_start","fieldName":"_start","visible":true},{"displayName":"_stop","fieldName":"_stop","visible":true},{"displayName":"_time","fieldName":"_time","visible":true},{"displayName":"_field","fieldName":"_field","visible":true},{"displayName":"_measurement","fieldName":"_measurement","visible":true},{"displayName":"engine_host","fieldName":"engine_host","visible":true},{"displayName":"role","fieldName":"role","visible":true},{"displayName":"server_version","fieldName":"server_version","visible":true},{"displayName":"container_image","fieldName":"container_image","visible":true},{"displayName":"container_version","fieldName":"container_version","visible":true},{"displayName":"description","fieldName":"description","visible":true},{"displayName":"maintainer","fieldName":"maintainer","visible":true},{"displayName":"io.k8s.description","fieldName":"io.k8s.description","visible":true},{"displayName":"io.k8s.display-name","fieldName":"io.k8s.display-name","visible":true},{"displayName":"license","fieldName":"license","visible":true},{"displayName":"name","fieldName":"name","visible":true},{"displayName":"org.label-schema.build-date","fieldName":"org.label-schema.build-date","visible":true},{"displayName":"org.label-schema.license","fieldName":"org.label-schema.license","visible":true},{"displayName":"org.label-schema.name","fieldName":"org.label-schema.name","visible":true},{"displayName":"org.label-schema.schema-version","fieldName":"org.label-schema.schema-version","visible":true},{"displayName":"org.label-schema.url","fieldName":"org.label-schema.url","visible":true},{"displayName":"org.label-schema.vcs-ref","fieldName":"org.label-schema.vcs-ref","visible":true},{"displayName":"org.label-schema.vcs-url","fieldName":"org.label-schema.vcs-url","visible":true},{"displayName":"org.label-schema.vendor","fieldName":"org.label-schema.vendor","visible":true},{"displayName":"org.label-schema.version","fieldName":"org.label-schema.version","visible":true},{"displayName":"org.opencontainers.image.created","fieldName":"org.opencontainers.image.created","visible":true},{"displayName":"org.opencontainers.image.licenses","fieldName":"org.opencontainers.image.licenses","visible":true},{"displayName":"org.opencontainers.image.title","fieldName":"org.opencontainers.image.title","visible":true},{"displayName":"org.opencontainers.image.vendor","fieldName":"org.opencontainers.image.vendor","visible":true},{"displayName":"release","fieldName":"release","visible":true},{"displayName":"summary","fieldName":"summary","visible":true},{"displayName":"url","fieldName":"url","visible":true},{"displayName":"vendor","fieldName":"vendor","visible":true},{"displayName":"version","fieldName":"version","visible":true},{"displayName":"org.label-schema.usage","fieldName":"org.label-schema.usage","visible":true},{"displayName":"org.opencontainers.image.documentation","fieldName":"org.opencontainers.image.documentation","visible":true},{"displayName":"org.opencontainers.image.revision","fieldName":"org.opencontainers.image.revision","visible":true},{"displayName":"org.opencontainers.image.source","fieldName":"org.opencontainers.image.source","visible":true},{"displayName":"org.opencontainers.image.url","fieldName":"org.opencontainers.image.url","visible":true},{"displayName":"org.opencontainers.image.version","fieldName":"org.opencontainers.image.version","visible":true},{"displayName":"org.opencontainers.image.description","fieldName":"org.opencontainers.image.description","visible":true}],"height":4,"kind":"Table","name":"Most Recent Container Events","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"docker_container_status\")\n |> filter(fn: (r) => r[\"_field\"] == \"oomkilled\")\n |> filter(fn: (r) => r[\"container_status\"] != \"running\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"container_name\", \"host\"])\n |> last()\n |> group()\n |> keep(columns: [\"_value\", \"container_name\", \"host\", \"container_status\"])"}],"staticLegend":{},"tableOptions":{"sortBy":"container_name","verticalTimeAxis":true},"timeFormat":"YYYY-MM-DD HH:mm:ss","width":3,"xPos":9,"yPos":6},{"axes":[{"base":"10","name":"x","scale":"linear"},{"name":"y","scale":"linear","suffix":"%"}],"colorizeRows":true,"colors":[{"id":"TtgHQAXNep94KBgtu48C_","name":"Cthulhu","type":"scale","hex":"#FDC44F"},{"id":"_IuzkORho_8QXTE6vMllv","name":"Cthulhu","type":"scale","hex":"#007C76"},{"id":"bUszW_YI_9oColDbLNQ-d","name":"Cthulhu","type":"scale","hex":"#8983FF"}],"geom":"line","height":4,"hoverDimension":"auto","kind":"Xy","legendColorizeRows":true,"legendOpacity":1,"legendOrientationThreshold":100000000,"name":"Zeek Capture Loss","opacity":1,"orientationThreshold":100000000,"position":"overlaid","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekcaptureloss\")\n |> filter(fn: (r) => r[\"_field\"] == \"loss\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"mean\")"},{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n\nroleFilter = (tables=<-) =>\n if v.Role != \"(All)\" then\n tables |> filter(fn: (r) => r[\"role\"] == v.Role)\n else\n tables\n\nfrom(bucket: \"telegraf/so_long_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"zeekcaptureloss\")\n |> filter(fn: (r) => r[\"_field\"] == \"loss\")\n |> hostFilter()\n |> roleFilter()\n |> group(columns: [\"_field\", \"host\", \"role\"])\n |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)\n |> yield(name: \"Trend\")"}],"staticLegend":{"colorizeRows":true,"opacity":1,"orientationThreshold":100000000,"widthRatio":1},"width":3,"widthRatio":1,"xCol":"_time","xPos":9,"yCol":"_value","yPos":42},{"colors":[{"id":"base","name":"laser","type":"text","hex":"#00C9FF"}],"decimalPlaces":1,"height":2,"kind":"Single_Stat","name":"PCAP Retention","queries":[{"query":"hostFilter = (tables=<-) =>\n if v.Host != \"(All)\" then\n tables |> filter(fn: (r) => r[\"host\"] == v.Host)\n else\n tables\n \nfrom(bucket: \"telegraf/so_short_term\")\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_measurement\"] == \"pcapage\")\n |> filter(fn: (r) => r[\"_field\"] == \"seconds\")\n |> hostFilter()\n |> map(fn: (r) => ({r with _value: r._value / (24.0 * 60.0 * 60.0)}))\n |> group(columns: [\"host\"])\n |> last()\n |> highestMax(n:1)"}],"staticLegend":{},"suffix":" days","width":1,"xPos":11}],"description":"Visualize the Security Onion grid performance metrics and alarm statuses.","name":"Security Onion Performance"}}] \ No newline at end of file diff --git a/salt/kafka/enabled.sls b/salt/kafka/enabled.sls index 8448bd5aa..06fa701c6 100644 --- a/salt/kafka/enabled.sls +++ b/salt/kafka/enabled.sls @@ -12,7 +12,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% set KAFKANODES = salt['pillar.get']('kafka:nodes') %} {% set KAFKA_EXTERNAL_ACCESS = salt['pillar.get']('kafka:config:external_access:enabled', default=False) %} {% if 'gmd' in salt['pillar.get']('features', []) %} @@ -31,22 +31,22 @@ so-kafka: - name: so-kafka - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-kafka'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-kafka'].ip }} - user: kafka - environment: KAFKA_HEAP_OPTS: -Xmx2G -Xms1G - KAFKA_OPTS: "-javaagent:/opt/jolokia/agents/jolokia-agent-jvm-javaagent.jar=port=8778,host={{ DOCKER.containers['so-kafka'].ip }},policyLocation=file:/opt/jolokia/jolokia.xml {%- if KAFKA_EXTERNAL_ACCESS %} -Djava.security.auth.login.config=/opt/kafka/config/kafka_server_jaas.conf {% endif -%}" + KAFKA_OPTS: "-javaagent:/opt/jolokia/agents/jolokia-agent-jvm-javaagent.jar=port=8778,host={{ DOCKERMERGED.containers['so-kafka'].ip }},policyLocation=file:/opt/jolokia/jolokia.xml {%- if KAFKA_EXTERNAL_ACCESS %} -Djava.security.auth.login.config=/opt/kafka/config/kafka_server_jaas.conf {% endif -%}" - extra_hosts: {% for node in KAFKANODES %} - {{ node }}:{{ KAFKANODES[node].ip }} {% endfor %} - {% if DOCKER.containers['so-kafka'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-kafka'].extra_hosts %} + {% if DOCKERMERGED.containers['so-kafka'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-kafka'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-kafka'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-kafka'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -60,6 +60,12 @@ so-kafka: {% if KAFKA_EXTERNAL_ACCESS %} - /opt/so/conf/kafka/kafka_server_jaas.conf:/opt/kafka/config/kafka_server_jaas.conf:ro {% endif %} + {% if DOCKERMERGED.containers['so-kafka'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-kafka'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: {% for sc in ['server', 'client'] %} - file: kafka_kraft_{{sc}}_properties @@ -68,6 +74,8 @@ so-kafka: - file: kafka_server_jaas_properties {% endif %} - file: kafkacertz + - x509: kafka_crt + - file: kafka_pkcs12_perms - require: - file: kafkacertz @@ -95,4 +103,4 @@ include: test.fail_without_changes: - name: {{sls}}_state_not_allowed -{% endif %} \ No newline at end of file +{% endif %} diff --git a/salt/kafka/soc_kafka.yaml b/salt/kafka/soc_kafka.yaml index cb093600f..b8d0c7c32 100644 --- a/salt/kafka/soc_kafka.yaml +++ b/salt/kafka/soc_kafka.yaml @@ -1,257 +1,258 @@ kafka: enabled: description: Set to True to enable Kafka. To avoid grid problems, do not enable Kafka until the related configuration is in place. Requires a valid Security Onion license key. - helpLink: kafka.html + forcedType: bool + helpLink: kafka cluster_id: description: The ID of the Kafka cluster. readonly: True advanced: True sensitive: True - helpLink: kafka.html + helpLink: kafka controllers: description: A comma-separated list of hostnames that will act as Kafka controllers. These hosts will be responsible for managing the Kafka cluster. Note that only manager and receiver nodes are eligible to run Kafka. This configuration needs to be set before enabling Kafka. Failure to do so may result in Kafka topics becoming unavailable requiring manual intervention to restore functionality or reset Kafka, either of which can result in data loss. forcedType: string - helpLink: kafka.html + helpLink: kafka reset: description: Disable and reset the Kafka cluster. This will remove all Kafka data including logs that may have not yet been ingested into Elasticsearch and reverts the grid to using REDIS as the global pipeline. This is useful when testing different Kafka configurations such as rearranging Kafka brokers / controllers allowing you to reset the cluster rather than manually fixing any issues arising from attempting to reassign a Kafka broker into a controller. Enter 'YES_RESET_KAFKA' and submit to disable and reset Kafka. Make any configuration changes required and re-enable Kafka when ready. This action CANNOT be reversed. advanced: True - helpLink: kafka.html + helpLink: kafka logstash: description: By default logstash is disabled when Kafka is enabled. This option allows you to specify any hosts you would like to re-enable logstash on alongside Kafka. forcedType: "[]string" multiline: True advanced: True - helpLink: kafka.html + helpLink: kafka config: password: description: The password used for the Kafka certificates. readonly: True sensitive: True - helpLink: kafka.html + helpLink: kafka trustpass: description: The password used for the Kafka truststore. readonly: True sensitive: True - helpLink: kafka.html + helpLink: kafka broker: auto_x_create_x_topics_x_enable: description: Enable the auto creation of topics. title: auto.create.topics.enable forcedType: bool - helpLink: kafka.html + helpLink: kafka default_x_replication_x_factor: description: The default replication factor for automatically created topics. This value must be less than the amount of brokers in the cluster. Hosts specified in controllers should not be counted towards total broker count. title: default.replication.factor forcedType: int - helpLink: kafka.html + helpLink: kafka inter_x_broker_x_listener_x_name: description: The name of the listener used for inter-broker communication. title: inter.broker.listener.name - helpLink: kafka.html + helpLink: kafka listeners: description: Set of URIs that is listened on and the listener names in a comma-seperated list. - helpLink: kafka.html + helpLink: kafka listener_x_security_x_protocol_x_map: description: Comma-seperated mapping of listener name and security protocols. title: listener.security.protocol.map - helpLink: kafka.html + helpLink: kafka log_x_dirs: description: Where Kafka logs are stored within the Docker container. title: log.dirs - helpLink: kafka.html + helpLink: kafka log_x_retention_x_check_x_interval_x_ms: description: Frequency at which log files are checked if they are qualified for deletion. title: log.retention.check.interval.ms - helpLink: kafka.html + helpLink: kafka log_x_retention_x_hours: description: How long, in hours, a log file is kept. title: log.retention.hours forcedType: int - helpLink: kafka.html + helpLink: kafka log_x_segment_x_bytes: description: The maximum allowable size for a log file. title: log.segment.bytes forcedType: int - helpLink: kafka.html + helpLink: kafka num_x_io_x_threads: description: The number of threads used by Kafka. title: num.io.threads forcedType: int - helpLink: kafka.html + helpLink: kafka num_x_network_x_threads: description: The number of threads used for network communication. title: num.network.threads forcedType: int - helpLink: kafka.html + helpLink: kafka num_x_partitions: description: The number of log partitions assigned per topic. title: num.partitions forcedType: int - helpLink: kafka.html + helpLink: kafka num_x_recovery_x_threads_x_per_x_data_x_dir: description: The number of threads used for log recuperation at startup and purging at shutdown. This ammount of threads is used per data directory. title: num.recovery.threads.per.data.dir forcedType: int - helpLink: kafka.html + helpLink: kafka offsets_x_topic_x_replication_x_factor: description: The offsets topic replication factor. title: offsets.topic.replication.factor forcedType: int - helpLink: kafka.html + helpLink: kafka process_x_roles: description: The role performed by Kafka brokers. title: process.roles readonly: True - helpLink: kafka.html + helpLink: kafka socket_x_receive_x_buffer_x_bytes: description: Size, in bytes of the SO_RCVBUF buffer. A value of -1 will use the OS default. title: socket.receive.buffer.bytes #forcedType: int - soc needs to allow -1 as an int before we can use this - helpLink: kafka.html + helpLink: kafka socket_x_request_x_max_x_bytes: description: The maximum bytes allowed for a request to the socket. title: socket.request.max.bytes forcedType: int - helpLink: kafka.html + helpLink: kafka socket_x_send_x_buffer_x_bytes: description: Size, in bytes of the SO_SNDBUF buffer. A value of -1 will use the OS default. title: socket.send.buffer.byte #forcedType: int - soc needs to allow -1 as an int before we can use this - helpLink: kafka.html + helpLink: kafka ssl_x_keystore_x_location: description: The key store file location within the Docker container. title: ssl.keystore.location - helpLink: kafka.html + helpLink: kafka ssl_x_keystore_x_password: description: The key store file password. Invalid for PEM format. title: ssl.keystore.password sensitive: True - helpLink: kafka.html + helpLink: kafka ssl_x_keystore_x_type: description: The key store file format. title: ssl.keystore.type regex: ^(JKS|PKCS12|PEM)$ - helpLink: kafka.html + helpLink: kafka ssl_x_truststore_x_location: description: The trust store file location within the Docker container. title: ssl.truststore.location - helpLink: kafka.html + helpLink: kafka ssl_x_truststore_x_type: description: The trust store file format. title: ssl.truststore.type - helpLink: kafka.html + helpLink: kafka ssl_x_truststore_x_password: description: The trust store file password. If null, the trust store file is still use, but integrity checking is disabled. Invalid for PEM format. title: ssl.truststore.password sensitive: True - helpLink: kafka.html + helpLink: kafka transaction_x_state_x_log_x_min_x_isr: description: Overrides min.insync.replicas for the transaction topic. When a producer configures acks to "all" (or "-1"), this setting determines the minimum number of replicas required to acknowledge a write as successful. Failure to meet this minimum triggers an exception (either NotEnoughReplicas or NotEnoughReplicasAfterAppend). When used in conjunction, min.insync.replicas and acks enable stronger durability guarantees. For instance, creating a topic with a replication factor of 3, setting min.insync.replicas to 2, and using acks of "all" ensures that the producer raises an exception if a majority of replicas fail to receive a write. title: transaction.state.log.min.isr forcedType: int - helpLink: kafka.html + helpLink: kafka transaction_x_state_x_log_x_replication_x_factor: description: Set the replication factor higher for the transaction topic to ensure availability. Internal topic creation will not proceed until the cluster size satisfies this replication factor prerequisite. title: transaction.state.log.replication.factor forcedType: int - helpLink: kafka.html + helpLink: kafka client: security_x_protocol: description: 'Broker communication protocol. Options are: SASL_SSL, PLAINTEXT, SSL, SASL_PLAINTEXT' title: security.protocol regex: ^(SASL_SSL|PLAINTEXT|SSL|SASL_PLAINTEXT) - helpLink: kafka.html + helpLink: kafka ssl_x_keystore_x_location: description: The key store file location within the Docker container. title: ssl.keystore.location - helpLink: kafka.html + helpLink: kafka ssl_x_keystore_x_password: description: The key store file password. Invalid for PEM format. title: ssl.keystore.password sensitive: True - helpLink: kafka.html + helpLink: kafka ssl_x_keystore_x_type: description: The key store file format. title: ssl.keystore.type regex: ^(JKS|PKCS12|PEM)$ - helpLink: kafka.html + helpLink: kafka ssl_x_truststore_x_location: description: The trust store file location within the Docker container. title: ssl.truststore.location - helpLink: kafka.html + helpLink: kafka ssl_x_truststore_x_type: description: The trust store file format. title: ssl.truststore.type - helpLink: kafka.html + helpLink: kafka ssl_x_truststore_x_password: description: The trust store file password. If null, the trust store file is still use, but integrity checking is disabled. Invalid for PEM format. title: ssl.truststore.password sensitive: True - helpLink: kafka.html + helpLink: kafka controller: controller_x_listener_x_names: description: Set listeners used by the controller in a comma-seperated list. title: controller.listener.names - helpLink: kafka.html + helpLink: kafka listeners: description: Set of URIs that is listened on and the listener names in a comma-seperated list. - helpLink: kafka.html + helpLink: kafka listener_x_security_x_protocol_x_map: description: Comma-seperated mapping of listener name and security protocols. title: listener.security.protocol.map - helpLink: kafka.html + helpLink: kafka log_x_dirs: description: Where Kafka logs are stored within the Docker container. title: log.dirs - helpLink: kafka.html + helpLink: kafka log_x_retention_x_check_x_interval_x_ms: description: Frequency at which log files are checked if they are qualified for deletion. title: log.retention.check.interval.ms - helpLink: kafka.html + helpLink: kafka log_x_retention_x_hours: description: How long, in hours, a log file is kept. title: log.retention.hours forcedType: int - helpLink: kafka.html + helpLink: kafka log_x_segment_x_bytes: description: The maximum allowable size for a log file. title: log.segment.bytes forcedType: int - helpLink: kafka.html + helpLink: kafka process_x_roles: description: The role performed by controller node. title: process.roles readonly: True - helpLink: kafka.html + helpLink: kafka external_access: enabled: description: Enables or disables access to Kafka topics using user/password authentication. Used for producing / consuming messages via an external client. forcedType: bool - helpLink: kafka.html + helpLink: kafka listeners: description: Set of URIs that is listened on and the listener names in a comma-seperated list. title: listeners readonly: True advanced: True - helpLink: kafka.html + helpLink: kafka listener_x_security_x_protocol_x_map: description: External listener name and mapped security protocol. title: listener.security.protocol.map readonly: True advanced: True - helpLink: kafka.html + helpLink: kafka sasl_x_enabled_x_mechanisms: description: SASL/PLAIN is a simple username/password authentication mechanism, used with TLS to implement secure authentication. title: sasl.enabled.mechanisms readonly: True advanced: True - helpLink: kafka.html + helpLink: kafka sasl_x_mechanism_x_inter_x_broker_x_protocol: description: SASL mechanism used for inter-broker communication title: sasl.mechanism.inter.broker.protocol readonly: True advanced: True - helpLink: kafka.html + helpLink: kafka remote_users: user01: &remote_user username: diff --git a/salt/kafka/ssl.sls b/salt/kafka/ssl.sls index 04b6b4ba7..2ee19f731 100644 --- a/salt/kafka/ssl.sls +++ b/salt/kafka/ssl.sls @@ -6,22 +6,13 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states or sls in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/map.jinja' import CA %} {% set kafka_password = salt['pillar.get']('kafka:config:password') %} include: - - ca.dirs - {% set global_ca_server = [] %} - {% set x509dict = salt['mine.get'](GLOBALS.manager | lower~'*', 'x509.get_pem_entries') %} - {% for host in x509dict %} - {% if 'manager' in host.split('_')|last or host.split('_')|last == 'standalone' %} - {% do global_ca_server.append(host) %} - {% endif %} - {% endfor %} - {% set ca_server = global_ca_server[0] %} + - ca -{% if GLOBALS.pipeline == "KAFKA" %} - -{% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone'] %} +{% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone'] %} kafka_client_key: x509.private_key_managed: - name: /etc/pki/kafka-client.key @@ -39,12 +30,12 @@ kafka_client_key: kafka_client_crt: x509.certificate_managed: - name: /etc/pki/kafka-client.crt - - ca_server: {{ ca_server }} + - ca_server: {{ CA.server }} - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - signing_policy: kafka - private_key: /etc/pki/kafka-client.key - CN: {{ GLOBALS.hostname }} - - days_remaining: 0 + - days_remaining: 7 - days_valid: 820 - backup: True - timeout: 30 @@ -67,9 +58,9 @@ kafka_client_crt_perms: - mode: 640 - user: 960 - group: 939 -{% endif %} +{% endif %} -{% if GLOBALS.role in ['so-manager', 'so-managersearch','so-receiver', 'so-standalone'] %} +{% if GLOBALS.role in ['so-manager', 'so-managersearch','so-receiver', 'so-standalone'] %} kafka_key: x509.private_key_managed: - name: /etc/pki/kafka.key @@ -87,12 +78,12 @@ kafka_key: kafka_crt: x509.certificate_managed: - name: /etc/pki/kafka.crt - - ca_server: {{ ca_server }} + - ca_server: {{ CA.server }} - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - signing_policy: kafka - private_key: /etc/pki/kafka.key - CN: {{ GLOBALS.hostname }} - - days_remaining: 0 + - days_remaining: 7 - days_valid: 820 - backup: True - timeout: 30 @@ -103,6 +94,7 @@ kafka_crt: - name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/kafka.key -in /etc/pki/kafka.crt -export -out /etc/pki/kafka.p12 -nodes -passout pass:{{ kafka_password }}" - onchanges: - x509: /etc/pki/kafka.key + kafka_key_perms: file.managed: - replace: False @@ -126,11 +118,11 @@ kafka_pkcs12_perms: - mode: 640 - user: 960 - group: 939 -{% endif %} +{% endif %} # Standalone needs kafka-logstash for automated testing. Searchnode/manager search need it for logstash to consume from Kafka. # Manager will have cert, but be unused until a pipeline is created and logstash enabled. -{% if GLOBALS.role in ['so-standalone', 'so-managersearch', 'so-searchnode', 'so-manager'] %} +{% if GLOBALS.role in ['so-standalone', 'so-managersearch', 'so-searchnode', 'so-manager'] %} kafka_logstash_key: x509.private_key_managed: - name: /etc/pki/kafka-logstash.key @@ -148,12 +140,12 @@ kafka_logstash_key: kafka_logstash_crt: x509.certificate_managed: - name: /etc/pki/kafka-logstash.crt - - ca_server: {{ ca_server }} + - ca_server: {{ CA.server }} - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - signing_policy: kafka - private_key: /etc/pki/kafka-logstash.key - CN: {{ GLOBALS.hostname }} - - days_remaining: 0 + - days_remaining: 7 - days_valid: 820 - backup: True - timeout: 30 @@ -189,7 +181,6 @@ kafka_logstash_pkcs12_perms: - user: 931 - group: 939 -{% endif %} {% endif %} {% else %} @@ -198,4 +189,4 @@ kafka_logstash_pkcs12_perms: test.fail_without_changes: - name: {{sls}}_state_not_allowed -{% endif %} \ No newline at end of file +{% endif %} diff --git a/salt/kibana/defaults.yaml b/salt/kibana/defaults.yaml index 078f826a0..580891973 100644 --- a/salt/kibana/defaults.yaml +++ b/salt/kibana/defaults.yaml @@ -25,11 +25,10 @@ kibana: discardCorruptObjects: "8.18.8" telemetry: enabled: False - security: - showInsecureClusterWarning: False xpack: security: secureCookies: true + showInsecureClusterWarning: false reporting: kibanaServer: hostname: localhost diff --git a/salt/kibana/enabled.sls b/salt/kibana/enabled.sls index 56aac26cc..04f44e508 100644 --- a/salt/kibana/enabled.sls +++ b/salt/kibana/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -20,20 +20,20 @@ so-kibana: - user: kibana - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-kibana'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-kibana'].ip }} - environment: - ELASTICSEARCH_HOST={{ GLOBALS.manager }} - ELASTICSEARCH_PORT=9200 - MANAGER={{ GLOBALS.manager }} - {% if DOCKER.containers['so-kibana'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-kibana'].extra_env %} + {% if DOCKERMERGED.containers['so-kibana'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-kibana'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} - extra_hosts: - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {% if DOCKER.containers['so-kibana'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-kibana'].extra_hosts %} + {% if DOCKERMERGED.containers['so-kibana'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-kibana'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} @@ -42,15 +42,21 @@ so-kibana: - /opt/so/log/kibana:/var/log/kibana:rw - /opt/so/conf/kibana/customdashboards:/usr/share/kibana/custdashboards:ro - /sys/fs/cgroup:/sys/fs/cgroup:ro - {% if DOCKER.containers['so-kibana'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-kibana'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-kibana'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-kibana'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-kibana'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-kibana'].port_bindings %} - {{ BINDING }} {% endfor %} + {% if DOCKERMERGED.containers['so-kibana'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-kibana'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: kibanaconfig diff --git a/salt/kibana/files/saved_objects.ndjson b/salt/kibana/files/saved_objects.ndjson index 7aabe4404..69d678fa8 100644 --- a/salt/kibana/files/saved_objects.ndjson +++ b/salt/kibana/files/saved_objects.ndjson @@ -475,7 +475,7 @@ {"attributes":{"columns":["_source"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"event.module:osquery\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["@timestamp","desc"]],"title":"Security Onion - Osquery","version":1},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"9eed5fc0-afcb-11ea-b262-353d451b125b","migrationVersion":{"search":"8.0.0"},"references":[{"id":"logs-*","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1689866817180,5707],"type":"search","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NDksMV0="} {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Security Onion - SIP - Content Type","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"title\":\"Security Onion - SIP - Content Type\",\"type\":\"table\",\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{\"emptyAsNull\":false},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"sip.content_type\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":100,\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"includeIsRegex\":true,\"excludeIsRegex\":true,\"customLabel\":\"Type\"},\"schema\":\"bucket\"}],\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMetricsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"percentageCol\":\"\",\"dimensions\":{\"metrics\":[{\"accessor\":1,\"format\":{\"id\":\"number\"},\"params\":{},\"label\":\"Count\",\"aggType\":\"count\"}],\"buckets\":[{\"accessor\":0,\"format\":{\"id\":\"terms\",\"params\":{\"id\":\"string\",\"otherBucketLabel\":\"Other\",\"missingBucketLabel\":\"Missing\",\"parsedUrl\":{\"origin\":\"https://PLACEHOLDER\",\"pathname\":\"/kibana/app/kibana\",\"basePath\":\"/kibana\"}}},\"params\":{},\"label\":\"sip.content_type.keyword: Descending\",\"aggType\":\"terms\"}]},\"showToolbar\":true,\"autoFitRowToContent\":false}}"},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"9ff24600-75ca-11ea-9565-7315f4ee5cac","migrationVersion":{"visualization":"8.5.0"},"references":[{"id":"logs-*","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1689866817180,5709],"type":"visualization","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTAsMV0="} {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"},"savedSearchRefName":"search_0","title":"OSSEC Alerts - Command (Data Table)","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"title\":\"OSSEC Alerts - Command (Data Table)\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\",\"showToolbar\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"command.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Command\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"username.keyword\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"Username\"}}]}"},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"9ff34f60-4a42-11e8-9b0a-f1d33346f773","migrationVersion":{"visualization":"8.5.0"},"references":[{"id":"d9096bb0-342f-11e7-9e93-53b62e1857b2","name":"search_0","type":"search"}],"sort":[1689866817180,5711],"type":"visualization","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTEsMV0="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":{\"match_all\":{}},\"language\":\"lucene\"},\"filter\":[]}"},"title":"Help","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Help\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"markdown\":\"## Introduction\\nWelcome to the Security Onion Elastic Stack! This is our implementation of the Elastic Stack on Security Onion. The Elastic Stack consists of three primary components:\\n- `Elasticsearch` - stores logs\\n- `Logstash` - collects and enriches logs before storing them in Elasticsearch\\n- `Kibana` - web interface for visualizing logs\\n\\n## Sidebar\\nStarting on the far left side of the page, you see the Sidebar. This contains links such as:\\n- `Discover` - search data\\n- `Visualize` - create visualizations based on searches\\n- `Dashboard` - view or create dashboards based on visualizations\\n- `Timelion` - timeline analysis\\n- `Dev Tools` - query Elasticsearch directly\\n- `Management` - view or modify Kibana settings\\n- `Squert` - separate web interface for viewing NIDS and HIDS alerts\\n- `Logout` - log out of your session\\n\\nThe first six of those links are within Kibana itself. If you click one of those and then want to get back to the Dashboards area where you started, simply click the `Dashboard` link.\\n\\nClicking the `Squert` link will take you out of Kibana and into Squert. You will not be required to authenticate to Squert since you already have an active Single Sign On (SSO) session.\\n\\nClicking the `Logout` link in either Squert or Kibana will log you out of your SSO session and take you back to the logon screen.\\n\\n## Navigation Panel\\nWhen you are in the Kibana Dashboard area, the panel to the immediate right of the sidebar is the Navigation Panel and it includes links to our dashboards such as Home, Help (this page), Bro Notices, ElastAlert, HIDS, NIDS, etc. Clicking one of the links in the Navigation Panel will take you to a dashboard dedicated to that particular log type. \\n\\n## Dashboards\\nAll dashboards are designed to work at 1024x768 screen resolution in order to maximize compatibility.\\n\\n### Dashboard Hyperlinks\\n\\nThe `source_ip` and `destination_ip` fields are hyperlinked. These hyperlinks will take you to the Indicator dashboard which will help you analyze the traffic relating to that particular IP address.\\n\\n`UID` fields are also hyperlinked. This hyperlink will start a new Kibana search for that particular UID. In the case of Bro UIDs this will show you all Bro logs related to that particular connection.\\n\\nEach log entry also has an `_id` field that is hyperlinked. This hyperlink will take you to CapMe, allowing you to request full packet capture for any arbitrary log type. This assumes that the log is for tcp or udp traffic that was seen by Bro and Bro recorded it correctly in its conn.log. \\n\\n### Overview Dashboard\\nWhen you first go to the Kibana Dashboard area, you are automatically placed into the Overview dashboard, where you will see overview information, such as total number of logs and sensors. Use the information on the Overview dashboard to determine which of the other dashboards on the Navigation Panel you might want to visit next.\\n\\n### Dashboard Categories\\nOur remaining dashboards are grouped into a few categories:\\n- `Alert Data` - dashboards that display alerts created by rules or signatures\\n- `Bro Hunting` - dashboards that allow you to slice and dice network metadata for hunting\\n- `Host Hunting` - dashboards that allow you to hunt via host telemetry\\n- `Other` - dashboards that don't fit into the categories above\\n\\n### Bro Notices\\nBro sniffs network traffic and generates notices such as `SSL::Invalid Server Cert` and `TeamCymruMalwareHashRegistry::Match`.\\n\\n### ElastAlert\\nElastAlert queries Elasticsearch on a regular basis and then generates alerts based on your desired criteria. Security Onion includes two example rules that alert on new IDS events and new connection logs. You can add your own ElastAlert rules in `/etc/elastalert/rules/`.\\n\\n### HIDS\\nOSSEC analyzes log files and generates Host Intrusion Detection System alerts based on its ruleset at `/var/ossec/rules/`. You can add your own rules in `/var/ossec/rules/local_rules.xml`.\\n\\n### NIDS\\nSecurity Onion can use either Snort or Suricata to sniff network traffic and generate Network Intrusion Detection System alerts. \\n\\n### Connections\\nBro sniffs network traffic and logs connection metadata including source IP/port, destination IP/port, protocol, and number of bytes.\\n\\n### DCE/RPC\\nBro sniffs network traffic and logs DCE/RPC metadata including source IP/port, destination IP/port, operation, endpoint, and named pipe.\\n\\n### DHCP\\nBro sniffs network traffic and logs DHCP requests and responses including source IP/port, destination IP/port, and MAC addresses.\\n\\n### DNP3\\nBro sniffs network traffic and logs DNP3 metadata including source IP/port, destination IP/port, function request, function reply.\\n\\n### DNS\\nBro sniffs network traffic and logs DNS queries and answers. Bro also includes other name lookups such as Windows NetBIOS name service requests and Bonjour.\\n\\n### Files\\nBro sniffs network traffic and logs metadata related to files being transferred over the network including IP addresses, MIME type, source, and checksums.\\n\\n### FTP\\nBro sniffs network traffic and logs FTP metadata including source IP/port, destination IP/port, command, reply code, argument, and username.\\n\\n### HTTP\\nBro sniffs network traffic and logs HTTP metadata including source IP/port, destination IP/port, method, status message, MIME type, site name, referer, and user agent.\\n\\n### Intel\\nBro sniffs network traffic and watches for indicators using the Intel framework. You can add your own indicators to `/opt/bro/share/bro/intel/intel.dat`.\\n\\n### IRC\\nBro sniffs network traffic and logs IRC metadata including source IP/port, destination IP/port, command, and username.\\n\\n### Kerberos\\nBro sniffs network traffic and logs Kerberos metadata including source IP/port, destination IP/port, cipher, client, server, service, request type, and success status.\\n\\n### Modbus\\nBro sniffs network traffic and logs Modbus metadata including source IP/port, destination IP/port, and function.\\n\\n### MySQL\\nBro sniffs network traffic and logs MySQL metadata including source IP/port, destination IP/port, command/argument, status, and response.\\n\\n### NTLM\\nBro sniffs network traffic and logs NTLM metadata including source IP/port, destination IP/port, hostname, username, and status.\\n\\n### PE\\nBro sniffs network traffic and logs PE metadata including OS, subsystem, machine, and section name.\\n\\n### RADIUS\\nBro sniffs network traffic and logs RADIUS metadata including source IP/port, destination IP/port, username, and result.\\n\\n### RDP\\nBro sniffs network traffic and logs RDP metadata including source IP/port, destination IP/port, client build, keyboard layout, encryption level, and result.\\n\\n### RFB\\nBro sniffs network traffic and logs RFB metadata including source IP/port, destination IP/port, authentication method, authentication status, client version, server version, and desktop name.\\n\\n### SIP\\nBro sniffs network traffic and logs SIP metadata including source IP/port, destination IP/port, method, content type, status, uri, and user agent.\\n\\n### SMB\\nBro sniffs network traffic and logs SMB metadata including source IP/port, destination IP/port, file name, and action.\\n\\n### SMTP\\nBro sniffs network traffic and logs SMTP metadata including source IP/port, destination IP/port, from, to, subject, and user agent.\\n\\n### SNMP\\nBro sniffs network traffic and logs SNMP metadata including source IP/port, destination IP/port, version, community, and duration.\\n\\n### Software\\nBro sniffs network traffic and logs metadata relating to the kinds of software that generated that traffic including name, type, and version.\\n\\n### SSH\\nBro sniffs network traffic and logs SSH metadata including source IP/port, destination IP/port, client version, server version, and success.\\n\\n### SSL\\nBro sniffs network traffic and logs SSL metadata including source IP/port, destination IP/port, server name, certificate subject, cipher, and validation status.\\n\\n### Syslog\\nBro sniffs network traffic and logs Syslog metadata including source IP/port, destination IP/port, severity, and protocol.\\n\\n### Tunnels\\nBro sniffs network traffic and detects IP, GRE, SOCKS, TEREDO, and AVAYA tunnels. It logs metadata including source IP/port, destination IP/port, type, and action.\\n\\n### Weird\\nBro sniffs network traffic and logs protocol anomalies metadata including source IP/port, destination IP/port, and the type of anomaly.\\n\\n### X.509\\nBro sniffs network traffic and logs X.509 metadata including certificate subject, issuer, key algorithm, key length, and signing algorithm.\\n\\n### Autoruns\\nSysinternals Autoruns can identify the processes which Windows is configured to automatically run. Autoruns data can then be ingested via [Autoruns To WinEventLog](https://github.com/palantir/windows-event-forwarding/tree/master/AutorunsToWinEventLog).\\n\\n### Beats\\nElastic Beats can be deployed on endpoints to collect host telemetry and send to Logstash for storage in Elasticsearch.\\n\\n### OSSEC\\nOSSEC agents can be deployed on endpoints to collect host telemetry and send to the OSSEC Server included in Security Onion. OSSEC Alerts can be found in the Alert Data category at the top of the Navigation Panel. This OSSEC hunting dashboard will allow you to hunt through all OSSEC logs, not just alerts.\\n\\n### Sysmon\\nSysinternal Sysmon provides comprehensive telemetry for Windows hosts. Its logs can be consumed using Beats, OSSEC, or other transport mechanism.\\n\\n### Domain Stats\\nSecurity Onion includes a tool called domain_stats which will do a whois lookup on a domain name to determine the age of the domain. If enabled, this dashboard looks for baby domains that have been recently registered. Please note that domain_stats is only enabled when running in Evaluation Mode.\\n\\n### Firewall\\nFirewall logs can be consumed via syslog or other transport mechanism. Once consumed, this dashboard allows you to slice and dice those firewall logs based on source IP/port, destination IP/port, protocol, and action.\\n\\n### Frequency\\nSecurity Onion includes a tool called freq_server which can perform frequency analysis of hostnames. If enabled, this dashboard will show hostnames with a frequency analysis score that indicates that they could have been randomly generated. Please note that freq_server is only enabled when running in Evaluation Mode.\\n\\n### Stats\\nThis dashboard shows statistics for Logstash including processing times for different log types and any errors that may have occurred.\\n\\n## More Information\\nFor additional information, please refer to our documentation at:\\n\\nhttps://securityonion.net/docs/Elastic\",\"type\":\"markdown\"},\"aggs\":[]}"},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"AV6-PHKnDwoBUzALqJ_c","migrationVersion":{"visualization":"8.5.0"},"references":[],"sort":[1689866817180,5712],"type":"visualization","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTIsMV0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":{\"match_all\":{}},\"language\":\"lucene\"},\"filter\":[]}"},"title":"Help","uiStateJSON":"{}","version":1,"visState":"{\"title\":\"Help\",\"type\":\"markdown\",\"params\":{\"fontSize\":12,\"markdown\":\"## Introduction\\nWelcome to the Security Onion Elastic Stack! This is our implementation of the Elastic Stack on Security Onion. The Elastic Stack consists of three primary components:\\n- `Elasticsearch` - stores logs\\n- `Logstash` - collects and enriches logs before storing them in Elasticsearch\\n- `Kibana` - web interface for visualizing logs\\n\\n## Sidebar\\nStarting on the far left side of the page, you see the Sidebar. This contains links such as:\\n- `Discover` - search data\\n- `Visualize` - create visualizations based on searches\\n- `Dashboard` - view or create dashboards based on visualizations\\n- `Timelion` - timeline analysis\\n- `Dev Tools` - query Elasticsearch directly\\n- `Management` - view or modify Kibana settings\\n- `Squert` - separate web interface for viewing NIDS and HIDS alerts\\n- `Logout` - log out of your session\\n\\nThe first six of those links are within Kibana itself. If you click one of those and then want to get back to the Dashboards area where you started, simply click the `Dashboard` link.\\n\\nClicking the `Squert` link will take you out of Kibana and into Squert. You will not be required to authenticate to Squert since you already have an active Single Sign On (SSO) session.\\n\\nClicking the `Logout` link in either Squert or Kibana will log you out of your SSO session and take you back to the logon screen.\\n\\n## Navigation Panel\\nWhen you are in the Kibana Dashboard area, the panel to the immediate right of the sidebar is the Navigation Panel and it includes links to our dashboards such as Home, Help (this page), Bro Notices, ElastAlert, HIDS, NIDS, etc. Clicking one of the links in the Navigation Panel will take you to a dashboard dedicated to that particular log type. \\n\\n## Dashboards\\nAll dashboards are designed to work at 1024x768 screen resolution in order to maximize compatibility.\\n\\n### Dashboard Hyperlinks\\n\\nThe `source_ip` and `destination_ip` fields are hyperlinked. These hyperlinks will take you to the Indicator dashboard which will help you analyze the traffic relating to that particular IP address.\\n\\n`UID` fields are also hyperlinked. This hyperlink will start a new Kibana search for that particular UID. In the case of Bro UIDs this will show you all Bro logs related to that particular connection.\\n\\nEach log entry also has an `_id` field that is hyperlinked. This hyperlink will take you to CapMe, allowing you to request full packet capture for any arbitrary log type. This assumes that the log is for tcp or udp traffic that was seen by Bro and Bro recorded it correctly in its conn.log. \\n\\n### Overview Dashboard\\nWhen you first go to the Kibana Dashboard area, you are automatically placed into the Overview dashboard, where you will see overview information, such as total number of logs and sensors. Use the information on the Overview dashboard to determine which of the other dashboards on the Navigation Panel you might want to visit next.\\n\\n### Dashboard Categories\\nOur remaining dashboards are grouped into a few categories:\\n- `Alert Data` - dashboards that display alerts created by rules or signatures\\n- `Bro Hunting` - dashboards that allow you to slice and dice network metadata for hunting\\n- `Host Hunting` - dashboards that allow you to hunt via host telemetry\\n- `Other` - dashboards that don't fit into the categories above\\n\\n### Bro Notices\\nBro sniffs network traffic and generates notices such as `SSL::Invalid Server Cert` and `TeamCymruMalwareHashRegistry::Match`.\\n\\n### ElastAlert\\nElastAlert queries Elasticsearch on a regular basis and then generates alerts based on your desired criteria. Security Onion includes two example rules that alert on new IDS events and new connection logs. You can add your own ElastAlert rules in `/etc/elastalert/rules/`.\\n\\n### HIDS\\nOSSEC analyzes log files and generates Host Intrusion Detection System alerts based on its ruleset at `/var/ossec/rules/`. You can add your own rules in `/var/ossec/rules/local_rules.xml`.\\n\\n### NIDS\\nSecurity Onion can use either Snort or Suricata to sniff network traffic and generate Network Intrusion Detection System alerts. \\n\\n### Connections\\nBro sniffs network traffic and logs connection metadata including source IP/port, destination IP/port, protocol, and number of bytes.\\n\\n### DCE/RPC\\nBro sniffs network traffic and logs DCE/RPC metadata including source IP/port, destination IP/port, operation, endpoint, and named pipe.\\n\\n### DHCP\\nBro sniffs network traffic and logs DHCP requests and responses including source IP/port, destination IP/port, and MAC addresses.\\n\\n### DNP3\\nBro sniffs network traffic and logs DNP3 metadata including source IP/port, destination IP/port, function request, function reply.\\n\\n### DNS\\nBro sniffs network traffic and logs DNS queries and answers. Bro also includes other name lookups such as Windows NetBIOS name service requests and Bonjour.\\n\\n### Files\\nBro sniffs network traffic and logs metadata related to files being transferred over the network including IP addresses, MIME type, source, and checksums.\\n\\n### FTP\\nBro sniffs network traffic and logs FTP metadata including source IP/port, destination IP/port, command, reply code, argument, and username.\\n\\n### HTTP\\nBro sniffs network traffic and logs HTTP metadata including source IP/port, destination IP/port, method, status message, MIME type, site name, referer, and user agent.\\n\\n### Intel\\nBro sniffs network traffic and watches for indicators using the Intel framework. You can add your own indicators to `/opt/bro/share/bro/intel/intel.dat`.\\n\\n### IRC\\nBro sniffs network traffic and logs IRC metadata including source IP/port, destination IP/port, command, and username.\\n\\n### Kerberos\\nBro sniffs network traffic and logs Kerberos metadata including source IP/port, destination IP/port, cipher, client, server, service, request type, and success status.\\n\\n### Modbus\\nBro sniffs network traffic and logs Modbus metadata including source IP/port, destination IP/port, and function.\\n\\n### MySQL\\nBro sniffs network traffic and logs MySQL metadata including source IP/port, destination IP/port, command/argument, status, and response.\\n\\n### NTLM\\nBro sniffs network traffic and logs NTLM metadata including source IP/port, destination IP/port, hostname, username, and status.\\n\\n### PE\\nBro sniffs network traffic and logs PE metadata including OS, subsystem, machine, and section name.\\n\\n### RADIUS\\nBro sniffs network traffic and logs RADIUS metadata including source IP/port, destination IP/port, username, and result.\\n\\n### RDP\\nBro sniffs network traffic and logs RDP metadata including source IP/port, destination IP/port, client build, keyboard layout, encryption level, and result.\\n\\n### RFB\\nBro sniffs network traffic and logs RFB metadata including source IP/port, destination IP/port, authentication method, authentication status, client version, server version, and desktop name.\\n\\n### SIP\\nBro sniffs network traffic and logs SIP metadata including source IP/port, destination IP/port, method, content type, status, uri, and user agent.\\n\\n### SMB\\nBro sniffs network traffic and logs SMB metadata including source IP/port, destination IP/port, file name, and action.\\n\\n### SMTP\\nBro sniffs network traffic and logs SMTP metadata including source IP/port, destination IP/port, from, to, subject, and user agent.\\n\\n### SNMP\\nBro sniffs network traffic and logs SNMP metadata including source IP/port, destination IP/port, version, community, and duration.\\n\\n### Software\\nBro sniffs network traffic and logs metadata relating to the kinds of software that generated that traffic including name, type, and version.\\n\\n### SSH\\nBro sniffs network traffic and logs SSH metadata including source IP/port, destination IP/port, client version, server version, and success.\\n\\n### SSL\\nBro sniffs network traffic and logs SSL metadata including source IP/port, destination IP/port, server name, certificate subject, cipher, and validation status.\\n\\n### Syslog\\nBro sniffs network traffic and logs Syslog metadata including source IP/port, destination IP/port, severity, and protocol.\\n\\n### Tunnels\\nBro sniffs network traffic and detects IP, GRE, SOCKS, TEREDO, and AVAYA tunnels. It logs metadata including source IP/port, destination IP/port, type, and action.\\n\\n### Weird\\nBro sniffs network traffic and logs protocol anomalies metadata including source IP/port, destination IP/port, and the type of anomaly.\\n\\n### X.509\\nBro sniffs network traffic and logs X.509 metadata including certificate subject, issuer, key algorithm, key length, and signing algorithm.\\n\\n### Autoruns\\nSysinternals Autoruns can identify the processes which Windows is configured to automatically run. Autoruns data can then be ingested via [Autoruns To WinEventLog](https://github.com/palantir/windows-event-forwarding/tree/master/AutorunsToWinEventLog).\\n\\n### Beats\\nElastic Beats can be deployed on endpoints to collect host telemetry and send to Logstash for storage in Elasticsearch.\\n\\n### OSSEC\\nOSSEC agents can be deployed on endpoints to collect host telemetry and send to the OSSEC Server included in Security Onion. OSSEC Alerts can be found in the Alert Data category at the top of the Navigation Panel. This OSSEC hunting dashboard will allow you to hunt through all OSSEC logs, not just alerts.\\n\\n### Sysmon\\nSysinternal Sysmon provides comprehensive telemetry for Windows hosts. Its logs can be consumed using Beats, OSSEC, or other transport mechanism.\\n\\n### Domain Stats\\nSecurity Onion includes a tool called domain_stats which will do a whois lookup on a domain name to determine the age of the domain. If enabled, this dashboard looks for baby domains that have been recently registered. Please note that domain_stats is only enabled when running in Evaluation Mode.\\n\\n### Firewall\\nFirewall logs can be consumed via syslog or other transport mechanism. Once consumed, this dashboard allows you to slice and dice those firewall logs based on source IP/port, destination IP/port, protocol, and action.\\n\\n### Frequency\\nSecurity Onion includes a tool called freq_server which can perform frequency analysis of hostnames. If enabled, this dashboard will show hostnames with a frequency analysis score that indicates that they could have been randomly generated. Please note that freq_server is only enabled when running in Evaluation Mode.\\n\\n### Stats\\nThis dashboard shows statistics for Logstash including processing times for different log types and any errors that may have occurred.\\n\\n## More Information\\nFor additional information, please refer to our documentation at:\\n\\nhttps://securityonion.net/docs/elasticsearch\",\"type\":\"markdown\"},\"aggs\":[]}"},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"AV6-PHKnDwoBUzALqJ_c","migrationVersion":{"visualization":"8.5.0"},"references":[],"sort":[1689866817180,5712],"type":"visualization","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTIsMV0="} {"attributes":{"fieldFormatMap":"{\"process_id\":{\"id\":\"number\",\"params\":{\"pattern\":\"0\"}},\"event_id\":{\"id\":\"number\",\"params\":{\"pattern\":\"0\"}}}","fields":"[{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"@version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"searchable\":false,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"aa\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"aa.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"action\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"action.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"activity_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"additional_info\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"additional_info.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"age\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"age.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"alert\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"alert.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"alert_level\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"alert_level.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"analyzer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"analyzer.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"answers\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"answers.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"apache2.access.body_sent.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.geoip.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.geoip.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.geoip.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.geoip.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.geoip.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.http_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.referrer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.remote_ip\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.response_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.device\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.major\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.minor\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.os_major\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.os_minor\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.os_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_agent.patch\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.access.user_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.client\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"apache2.error.module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.tid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"apache2.error.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"assigned_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"assigned_ip.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.a0\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.acct\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.geoip.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.geoip.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.geoip.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.geoip.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.geoip.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.item\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.items\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.new_auid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.new_ses\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.old_auid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.old_ses\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.pid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.ppid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.record_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.res\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auditd.log.sequence\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"auth\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"auth.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"authentication_attempts\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"authentication_method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"authentication_method.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"authentication_success\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"authentication_success.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"basic_constraints_ca\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"basic_constraints_ca.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"basic_constraints_path_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"beat.hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"beat.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"beat.timezone\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"beat.version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"bound_port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"call_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"call_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"category\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"category.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cc\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"cc.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_chain_fuids\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_chain_fuids.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_common_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_common_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_common_name_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_common_name_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_curve\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_curve.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_exponent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_exponent.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_issuer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_issuer.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_key_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_key_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_key_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_key_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_key_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_locality\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_locality.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_not_valid_after\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_not_valid_before\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_number_days_valid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_organization\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_organization.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_organization_unit\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_organization_unit.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_permanent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_permanent.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_serial\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_serial.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_serial_number\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_serial_number.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_signing_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_signing_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_state.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_subject\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_subject.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"certificate_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"certificate_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"checksum\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"checksum.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cipher\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"cipher.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cipher_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"cipher_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"class\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"class.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"classification\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"classification.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_build\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_build.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_certificate_chain_fuids\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_certificate_chain_fuids.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_certificate_fuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_certificate_fuid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_certificate_subject\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_certificate_subject.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_digital_product_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_digital_product_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_issuer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_issuer.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_major_version\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_major_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_minor_version\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_minor_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"client_subject\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"client_subject.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"command\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"command.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"community\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"community.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"company\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"company.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"compile_ts\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"compile_ts.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"compression_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"compression_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"computer_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"computer_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"connect_info\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"connect_info.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"connection_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"connection_state.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"connection_state_description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"connection_state_description.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"content_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"content_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"cookie\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"cookie.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"creation_date\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"creation_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"current_directory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"current_directory.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"curve\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"curve.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_channel_destination_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_channel_destination_port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_channel_passive\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"data_channel_passive.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_channel_source_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"data_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"date\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dcc_file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dcc_file_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dcc_file_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dcc_mime_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dcc_mime_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"depth\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"description.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"desktop_height\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"desktop_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"desktop_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"desktop_width\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dest_is_ipv6\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dest_is_ipv6.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_city\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_city.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.city_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.continent_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.continent_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.country_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.country_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.dma_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.latitude\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.longitude\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.longitude.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.postal_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.postal_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.region_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.region_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.region_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_geo.timezone\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_geo.timezone.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_hostname.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_ips\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_ips.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_latitude\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_latitude.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_longitude\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_longitude.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_port_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_port_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"destination_region\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"destination_region.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"details\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"details.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dir\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dir.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"direction\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"direction.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"display_string\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"display_string.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"docker.container.id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"docker.container.image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"docker.container.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"domain_age\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"domain_age.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"domain_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"domain_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"dropped\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"dropped.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"duration\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"enabled\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"enabled.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"encryption_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"encryption_level.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"encryption_method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"encryption_method.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"endpoint\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"endpoint.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"entry\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"entry.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"entry_location\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"entry_location.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"error.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"error_message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"error_message.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"escalated_user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"escalated_user.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"established\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"established.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.AccountName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.AlgorithmName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.AuthenticationPackageName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Binary\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.CommandLine\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Configuration\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ConfigurationFileHash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.CreationUtcTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.CurrentDirectory\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DestinationIp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DestinationIsIpv6\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DestinationPort\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Details\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DeviceName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DeviceNameLength\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DeviceTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DeviceVersionMajor\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DeviceVersionMinor\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.DirtyPages\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ElevatedToken\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.EventType\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ExtraInfoLength\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ExtraInfoString\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.FilterID\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.FinalStatus\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Hash\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Hashes\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.HiveName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.HiveNameLength\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ImagePath\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ImpersonationLevel\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Initiated\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.IntegrityLevel\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.IpAddress\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.IpPort\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.KeyFilePath\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.KeyLength\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.KeyName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.KeyType\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.KeysUpdated\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.LmPackageName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.LogonGuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.LogonId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.LogonProcessName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.LogonType\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.NewSize\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.NewTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.OldTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Operation\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.OriginalSize\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ParentCommandLine\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ParentImage\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ParentProcessGuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ParentProcessId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.PreviousCreationUtcTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.PreviousTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.PrivilegeList\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ProcessGuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ProcessId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ProcessName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Protocol\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ProviderName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Reason\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.RestrictedAdminMode\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ReturnCode\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SchemaVersion\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ServiceName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.ServiceType\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SourceHostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SourceIp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SourceIsIpv6\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SourcePort\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.StartType\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.State\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SubjectDomainName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SubjectLogonId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SubjectUserName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.SubjectUserSid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetDomainName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetFilename\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetLinkedLogonId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetLogonId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetObject\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetOutboundDomainName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetOutboundUserName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetUserName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TargetUserSid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TerminalSessionId\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.TransmittedServices\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.User\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.UtcTime\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.VirtualAccount\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.Workstation\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.WorkstationName\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param10\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param11\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param12\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param13\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param14\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param15\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param16\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param17\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param19\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param2\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param20\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param21\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param22\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param3\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param4\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param6\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param7\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param8\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.param9\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.serviceGuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.updateGuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.updateRevisionNumber\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_data.updateTitle\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"event_timestamp.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"event_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"event_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"exception\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"exception.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"extracted\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"extracted.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"facility\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"facility.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"fc_reply\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"fc_reply.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"fc_request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"fc_request.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file_description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"file_description.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file_ip.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file_mime_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"file_mime_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"file_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"file_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"fileset.module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"fileset.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"first_received\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"first_received.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"flow_label\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"flow_label.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"forwardable\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"forwardable.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"freq_virtual_host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"freq_virtual_host.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"frequency_scores\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"frequency_scores.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"from\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"from.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ftp_argument\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ftp_argument.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ftp_command\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ftp_command.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"fuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"fuid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"fuids\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"fuids.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"function\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"function.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.latitude\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"geoip.longitude\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"get_bulk_requests\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"get_bulk_requests.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"get_requests\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"get_requests.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"gid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"has_cert_table\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"has_cert_table.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"has_debug_data\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"has_debug_data.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"has_export_table\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"has_export_table.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"has_import_table\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"has_import_table.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"height\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"helo\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"helo.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"highest_registered_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"highest_registered_domain.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"highest_registered_domain_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"history\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"history.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hop_limit\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"hop_limit.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host_key\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host_key.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"host_key_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"host_key_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"hostname.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icinga.debug.facility\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icinga.debug.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"icinga.debug.severity\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icinga.main.facility\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icinga.main.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"icinga.main.severity\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icinga.startup.facility\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"icinga.startup.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"icinga.startup.severity\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"iin\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"iin.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"image_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"image_path.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"in_reply_to\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"in_reply_to.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"indicator\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"indicator.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"indicator_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"indicator_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"info_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"info_message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"info_message.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"initiated\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"initiated.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"integrity_level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"integrity_level.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"interface\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"interface.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ip_version\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ips\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ips.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_flags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipv4_flags.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipv4_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_offset\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipv4_offset.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_protocol\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipv4_protocol.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_protocol_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipv4_protocol_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_protocol_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_tos\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ipv4_tos.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ipv4_ttl\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"irc_command\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"irc_command.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"is_64bit\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"is_64bit.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"is_exe\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"is_exe.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"is_orig\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"is_orig.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"is_source_ipv6\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"is_source_ipv6.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"is_webmail\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"is_webmail.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_common_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_common_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_common_name_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_common_name_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_distinguished_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_distinguished_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_locality\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_locality.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_organization\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_organization.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_organization_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_organization_unit\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_organization_unit.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_serial_number\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_serial_number.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"issuer_state\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"issuer_state.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kafka.log.class\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"kafka.log.component\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kafka.log.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kafka.log.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"kafka.log.timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kafka.log.trace.class\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kafka.log.trace.full\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"kafka.log.trace.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"kerberos_success\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"kerberos_success.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kex_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"kex_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"keyboard_layout\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"keyboard_layout.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"keywords\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.container.image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.container.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.namespace\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"kubernetes.pod.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"last_alert\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"last_alert.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"last_reply\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"last_reply.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"launch_string\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"launch_string.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"lease_time\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"lease_time.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"length\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"length.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"local_orig\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"local_orig.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"local_respond\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"local_respond.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"location\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"location.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"log_timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"log_timestamp.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logged\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logged.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logon_guid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logon_guid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logon_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logon_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.log.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.log.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logstash.log.module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.log.thread\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logstash.slowlog.event\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logstash.slowlog.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.slowlog.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logstash.slowlog.module\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.slowlog.plugin_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.slowlog.plugin_params\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logstash.slowlog.plugin_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.slowlog.thread\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"logstash.slowlog.took_in_millis\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash.slowlog.took_in_nanos\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"logstash_time\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mac\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mac.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mac_algorithm\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mac_algorithm.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"machine\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"machine.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mail_date\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mail_date.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mail_from\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mail_from.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"matched\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"matched.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"md5\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"md5.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"message.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message_error\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"message_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"message_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.availability_zone\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.instance_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.instance_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.machine_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.project_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.provider\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"meta.cloud.region\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"method.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mimetype\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mimetype.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"missed_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"missing_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"msg\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"msg.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.error.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.error.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mysql.error.thread_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.error.timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.ip\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.lock_time.sec\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.query\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.query_time.sec\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.rows_examined\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.rows_sent\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.timestamp\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql.slowlog.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql_argument\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mysql_argument.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql_command\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mysql_command.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"mysql_success\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"mysql_success.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"n\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"named_pipe\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"named_pipe.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"native_file_system\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"native_file_system.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"next_protocol\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"next_protocol.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"nginx.access.body_sent.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.geoip.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.geoip.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.geoip.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.geoip.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.geoip.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.http_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.referrer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.remote_ip\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.response_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.device\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.major\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.minor\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.os_major\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.os_minor\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.os_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_agent.patch\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.access.user_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.error.connection_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.error.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.error.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"nginx.error.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nginx.error.tid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"nick\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"nick.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"note\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"note.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"notice\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"notice.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ntlm_success\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ntlm_success.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"num_packets\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"object_size\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"offset\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"opcode\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"operation\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"operation.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"orig_filenames\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"orig_filenames.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"orig_fuids\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"orig_fuids.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"orig_mime_types\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"orig_mime_types.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"original_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"original_country_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"original_country_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"original_ip_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"original_packets\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"os.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ossec_agent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ossec_agent_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ossec_timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ossec_timestamp.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"overflow_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"p\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"parent_domain.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_domain_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_domain_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_image_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"parent_image_path.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_process_guid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"parent_process_guid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_process_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"parent_process_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"parent_process_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"parent_process_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"password\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"password.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"path.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"peer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"peer.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"peer_description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"peer_description.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pesha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"pesha1.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pesha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"pesha256.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"pid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"port\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.database\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.duration\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"postgresql.log.query\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.thread_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.timezone\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"postgresql.log.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"prev_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"prev_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"priority\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"priority.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"process.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process_arguments\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"process_arguments.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process_guid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"process_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"process_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"profile\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"profile.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"program\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"program.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"prospector.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"protocol\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"protocol.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"protocol_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"protocol_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"protocol_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"protocol_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"provider_guid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"proxied\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"proxied.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"query\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"query.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"query_class\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"query_class_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"query_class_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"query_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"query_type\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"query_type_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"query_type_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ra\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"ra.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rcode\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rcode_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rcode_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rd\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rd.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"read_timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"reason\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"reason.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"recipient_to\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"recipient_to.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"record_number\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.log.level\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.log.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"redis.log.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.log.role\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.slowlog.args\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.slowlog.cmd\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.slowlog.duration.us\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.slowlog.id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"redis.slowlog.key\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"referrer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"referrer.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rejected\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rejected.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"related_activity_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"remote_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"renewable\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"renewable.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"reply_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"reply_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"reply_message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"reply_message.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"reply_to\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"reply_to.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_body_len\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_body_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_from\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request_path.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_port\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request_port\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request_timestamp.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_to\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request_to.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"request_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"request_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"requested_color_depth\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"requested_color_depth.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"requested_resource\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"requested_resource.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"resp_filenames\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resp_filenames.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"resp_fuids\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resp_fuids.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"resp_mime_types\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resp_mime_types.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"respond_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"respond_ip_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"respond_packets\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response_body_len\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response_body_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response_from\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response_from.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response_path\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response_path.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"response_to\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"response_to.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"result\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"result.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"resumed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"resumed.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rev\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rev.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rig\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rig.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rows\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rows.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rtt\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rtt.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rule.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule_number\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"rule_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"rule_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"san_dns\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"san_dns.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"second_received\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"second_received.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"section_names\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"section_names.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"security_protocol\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"security_protocol.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"seen_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"seen_node\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"seen_node.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"seen_where\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"seen_where.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sensor_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sensor_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"seq\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"seq.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"server.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_certificate_fuid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"server_certificate_fuid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_certificate_subject\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"server_certificate_subject.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_major_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"server_major_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_minor_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"server_minor_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"server_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_name_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"server_name_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"service\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"service.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"set_requests\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"set_requests.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"severity\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"severity.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sha1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sha1.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sha256\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sha256.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"share_flag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"share_flag.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"share_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"share_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"signature_info\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"signer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"signer.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"site.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"size\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"size.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"software_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"software_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_geo.city_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.continent_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_geo.continent_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.dma_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.latitude\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.longitude\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.postal_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_geo.postal_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.region_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_geo.region_code.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_geo.region_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_geo.timezone\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_geo.timezone.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_hostname.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_ips\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_ips.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"source_port_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"source_port_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sources\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sources.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"status.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"status_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"status_message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"status_message.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"status_msg\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"status_msg.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"stream\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sub_msg\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sub_msg.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sub_rule_number\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sub_rule_number.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"subdomain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"subdomain.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"subdomain_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"subdomain_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"subject\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"subject.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"subsystem\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"subsystem.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"suppress_for\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-facility\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-facility.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-file_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-file_name.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-host.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-host_from\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-host_from.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-legacy_msghdr\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-legacy_msghdr.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-pid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-pid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-priority\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-priority.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-sourceip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"syslog-tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"syslog-tags.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"sysmon_timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"sysmon_timestamp.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.groupadd.gid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.groupadd.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.pid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.program\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.dropped_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.event\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.geoip.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.geoip.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.geoip.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.geoip.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.geoip.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.port\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.ssh.signature\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.sudo.command\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.sudo.error\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.sudo.pwd\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.sudo.tty\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.sudo.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.user\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.useradd.gid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.useradd.home\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.useradd.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.useradd.shell\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.auth.useradd.uid\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.syslog.hostname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.syslog.message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.syslog.pid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.syslog.program\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"system.syslog.timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tags.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"target_filename\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"target_filename.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"task\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tc\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tc.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"terminal_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"terminal_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"thread_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timed_out\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"timed_out.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"times_accessed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"times_accessed.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"times_changed\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"times_changed.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"times_created\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"times_created.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"times_modified\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"times_modified.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"timestamp\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"timestamp.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tld.subdomain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tld.subdomain.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tls\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tls.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"to\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"to.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"top_level_domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"top_level_domain.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"total_bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tracker_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tracker_id.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"traefik.access.backend_url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"traefik.access.body_sent.bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.frontend_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"traefik.access.geoip.city_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.geoip.continent_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.geoip.country_iso_code\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.geoip.location\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.geoip.region_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.http_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.method\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.referrer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.remote_ip\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.request_count\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.response_code\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.device\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.major\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.minor\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.os_major\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.os_minor\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.os_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_agent.patch\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"traefik.access.user_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"trans_depth\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"transaction_id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"ttls\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tty\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tty.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tunnel_parents\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tunnel_parents.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"tunnel_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"tunnel_type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"type.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uid\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"uid.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"unparsed_version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"unparsed_version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"up_since\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"up_since.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uri\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"uri.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uri_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.domain\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.identifier\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user.type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"user_agent.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_data.binaryData\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_data.binaryDataSize\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_data.param1\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_data.param2\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"user_data.xml_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"useragent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"useragent.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"useragent_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"username\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"username.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uses_aslr\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"uses_aslr.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uses_code_integrity\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"uses_code_integrity.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uses_dep\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"uses_dep.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"uses_seh\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"uses_seh.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"valid_from\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"valid_from.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"valid_till\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"valid_till.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"validation_status\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"validation_status.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"value\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"value.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version_additional_info\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"version_additional_info.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version_major\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"version_major.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version_minor\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"version_minor.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version_minor2\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"version_minor2.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"version_minor3\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"version_minor3.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"virtual_host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"virtual_host.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"virtual_host_frequency_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"virtual_host_length\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"warning\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"warning.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"width.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"x_originating_ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"xml\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"year\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true},{\"name\":\"z\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":false,\"readFromDocValues\":false},{\"name\":\"z.keyword\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":true}]","notExpandable":true,"timeFieldName":"@timestamp","title":"*:logstash-beats-*"},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"AWBLHZaBRuBloj96jvrD","migrationVersion":{"index-pattern":"8.0.0"},"references":[],"sort":[1689866817180,5713],"type":"index-pattern","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTMsMV0="} {"attributes":{"columns":["computer_name","process_id","user.name","event_id","event_data.Image"],"description":"","hits":0,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"highlightAll\":true,\"version\":true,\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"sort":[["@timestamp","desc"]],"title":"All Beats Logs","version":1},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"AWBLMr9vRuBloj96jxp1","migrationVersion":{"search":"8.0.0"},"references":[{"id":"AWBLHZaBRuBloj96jvrD","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1689866817180,5715],"type":"search","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTQsMV0="} {"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"title":"Beats - Process IDs","uiStateJSON":"{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}","version":1,"visState":"{\"title\":\"Beats - Process IDs\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showMeticsAtAllLevels\":false,\"showPartialRows\":false,\"showTotal\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"totalFunc\":\"sum\",\"type\":\"table\",\"showToolbar\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"process_id\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\"}}],\"listeners\":{}}"},"coreMigrationVersion":"8.7.1","created_at":"2023-07-20T15:26:57.180Z","id":"AWBLN7X2RuBloj96jxxY","migrationVersion":{"visualization":"8.5.0"},"references":[{"id":"AWBLHZaBRuBloj96jvrD","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"sort":[1689866817180,5717],"type":"visualization","updated_at":"2023-07-20T15:26:57.180Z","version":"WzQ1NTUsMV0="} diff --git a/salt/kibana/map.jinja b/salt/kibana/map.jinja index bd333f1c4..b2e94806d 100644 --- a/salt/kibana/map.jinja +++ b/salt/kibana/map.jinja @@ -5,7 +5,6 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} {% import_yaml 'kibana/defaults.yaml' as KIBANADEFAULTS with context %} -{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} {% do KIBANADEFAULTS.kibana.config.server.update({'publicBaseUrl': 'https://' ~ GLOBALS.url_base ~ '/kibana'}) %} {% do KIBANADEFAULTS.kibana.config.elasticsearch.update({'hosts': ['https://' ~ GLOBALS.manager ~ ':9200']}) %} diff --git a/salt/kibana/so_dashboard_load.sls b/salt/kibana/so_dashboard_load.sls index 3222eabc6..7f733e7c6 100644 --- a/salt/kibana/so_dashboard_load.sls +++ b/salt/kibana/so_dashboard_load.sls @@ -3,7 +3,6 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} include: - kibana.enabled @@ -29,27 +28,3 @@ so-kibana-dashboard-load: - require: - sls: kibana.enabled - file: dashboard_saved_objects_template -{%- if HIGHLANDER %} -dashboard_saved_objects_template_hl: - file.managed: - - name: /opt/so/conf/kibana/hl.ndjson.template - - source: salt://kibana/files/hl.ndjson - - user: 932 - - group: 939 - - show_changes: False - -dashboard_saved_objects_hl_changes: - file.absent: - - names: - - /opt/so/state/kibana_hl.txt - - onchanges: - - file: dashboard_saved_objects_template_hl - -so-kibana-dashboard-load_hl: - cmd.run: - - name: /usr/sbin/so-kibana-config-load -i /opt/so/conf/kibana/hl.ndjson.template - - cwd: /opt/so - - require: - - sls: kibana.enabled - - file: dashboard_saved_objects_template_hl -{%- endif %} diff --git a/salt/kibana/soc_kibana.yaml b/salt/kibana/soc_kibana.yaml index 2c097ce1c..168830bbd 100644 --- a/salt/kibana/soc_kibana.yaml +++ b/salt/kibana/soc_kibana.yaml @@ -1,10 +1,46 @@ kibana: - enabled: + enabled: description: Enables or disables the Kibana front-end interface to Elasticsearch. Due to Kibana being used for loading certain configuration details in Elasticsearch, this process should remain enabled. WARNING - Disabling the process is unsupported, and will cause unexpected results. - helpLink: kibana.html + forcedType: bool + helpLink: kibana config: + server: + rewriteBasePath: + description: Specifies whether Kibana should rewrite requests that are prefixed with the server basePath. + forcedType: bool + global: True + advanced: True + helpLink: kibana elasticsearch: requestTimeout: description: The length of time before the request reaches timeout. global: True - helpLink: kibana.html + helpLink: kibana + telemetry: + enabled: + description: Enables or disables telemetry data collection in Kibana. + forcedType: bool + global: True + advanced: True + helpLink: kibana + xpack: + security: + secureCookies: + description: Sets the secure flag on session cookies. Cookies are only sent over HTTPS when enabled. + forcedType: bool + global: True + advanced: True + helpLink: kibana + showInsecureClusterWarning: + description: Shows a warning in Kibana when the cluster does not have security enabled. + forcedType: bool + global: True + advanced: True + helpLink: kibana + apm: + enabled: + description: Enables or disables the APM agent in Kibana. + forcedType: bool + global: True + advanced: True + helpLink: kibana diff --git a/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults b/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults index cbd16a2de..fcb80e606 100755 --- a/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults +++ b/salt/kibana/tools/sbin_jinja/so-kibana-space-defaults @@ -1,6 +1,5 @@ #!/bin/bash . /usr/sbin/so-common -{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} wait_for_web_response "http://localhost:5601/api/spaces/space/default" "default" 300 "curl -K /opt/so/conf/elasticsearch/curl.config" ## This hackery will be removed if using Elastic Auth ## @@ -9,10 +8,6 @@ SESSIONCOOKIE=$(curl -K /opt/so/conf/elasticsearch/curl.config -c - -X GET http: # Disable certain Features from showing up in the Kibana UI echo -echo "Setting up default Space:" -{% if HIGHLANDER %} -curl -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["enterpriseSearch"]} ' >> /opt/so/log/kibana/misc.log -{% else %} +echo "Setting up default Kibana Space:" curl -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -L -X PUT "localhost:5601/api/spaces/space/default" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d' {"id":"default","name":"Default","disabledFeatures":["ml","enterpriseSearch","logs","infrastructure","apm","uptime","monitoring","stackAlerts","actions","securitySolutionCasesV3","inventory","dataQuality","searchSynonyms","enterpriseSearchApplications","enterpriseSearchAnalytics","securitySolutionTimeline","securitySolutionNotes","entityManager"]} ' >> /opt/so/log/kibana/misc.log -{% endif %} echo diff --git a/salt/kratos/config.sls b/salt/kratos/config.sls index b9f5142f1..622522e0b 100644 --- a/salt/kratos/config.sls +++ b/salt/kratos/config.sls @@ -75,6 +75,7 @@ kratosconfig: - group: 928 - mode: 600 - template: jinja + - show_changes: False - defaults: KRATOSMERGED: {{ KRATOSMERGED }} diff --git a/salt/kratos/defaults.yaml b/salt/kratos/defaults.yaml index 598a94fa1..b70141b6f 100644 --- a/salt/kratos/defaults.yaml +++ b/salt/kratos/defaults.yaml @@ -46,6 +46,7 @@ kratos: ui_url: https://URL_BASE/ login: ui_url: https://URL_BASE/login/ + lifespan: 60m error: ui_url: https://URL_BASE/login/ registration: diff --git a/salt/kratos/enabled.sls b/salt/kratos/enabled.sls index f0345edec..35587a520 100644 --- a/salt/kratos/enabled.sls +++ b/salt/kratos/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -19,32 +19,38 @@ so-kratos: - name: so-kratos - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-kratos'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-kratos'].ip }} - binds: - /opt/so/conf/kratos/:/kratos-conf:ro - /opt/so/log/kratos/:/kratos-log:rw - /nsm/kratos/db:/kratos-data:rw - {% if DOCKER.containers['so-kratos'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-kratos'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-kratos'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-kratos'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-kratos'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-kratos'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-kratos'].extra_hosts %} + {% if DOCKERMERGED.containers['so-kratos'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-kratos'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-kratos'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-kratos'].extra_env %} + {% if DOCKERMERGED.containers['so-kratos'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-kratos'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-kratos'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-kratos'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-kratos'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - restart_policy: unless-stopped - watch: - file: kratosschema diff --git a/salt/kratos/soc_kratos.yaml b/salt/kratos/soc_kratos.yaml index bc95d9b03..1cd2728c8 100644 --- a/salt/kratos/soc_kratos.yaml +++ b/salt/kratos/soc_kratos.yaml @@ -1,88 +1,91 @@ kratos: enabled: description: Enables or disables the Kratos authentication system. WARNING - Disabling this process will cause the grid to malfunction. Re-enabling this setting will require manual effort via SSH. + forcedType: bool advanced: True - helpLink: kratos.html + helpLink: kratos oidc: - enabled: + enabled: description: Set to True to enable OIDC / Single Sign-On (SSO) to SOC. Requires a valid Security Onion license key. + forcedType: bool global: True - helpLink: oidc.html + helpLink: oidc config: id: description: Customize the OIDC provider name. This name appears on the login page. Required. It is strongly recommended to leave this to the default value, unless you are aware of the other configuration pieces that will be affected by changing it. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc provider: description: "Specify the provider type. Required. Valid values are: auth0, generic, github, google, microsoft" global: True forcedType: string regex: "auth0|generic|github|google|microsoft" regexFailureMessage: "Valid values are: auth0, generic, github, google, microsoft" - helpLink: oidc.html + helpLink: oidc client_id: description: Specify the client ID, also referenced as the application ID. Required. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc client_secret: description: Specify the client secret. Required. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc microsoft_tenant: description: Specify the Microsoft Active Directory Tenant ID. Required when provider is 'microsoft'. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc subject_source: description: The source of the subject identifier. Typically 'userinfo'. Only used when provider is 'microsoft'. global: True forcedType: string regex: me|userinfo regexFailureMessage: "Valid values are: me, userinfo" - helpLink: oidc.html + helpLink: oidc auth_url: description: Provider's auth URL. Required when provider is 'generic'. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc issuer_url: description: Provider's issuer URL. Required when provider is 'auth0' or 'generic'. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc mapper_url: description: A file path or URL in Jsonnet format, used to map OIDC claims to the Kratos schema. Defaults to an included file that maps the email claim. Note that the contents of the included file can be customized via the "OIDC Claims Mapping" setting. advanced: True global: True forcedType: string - helpLink: oidc.html + helpLink: oidc token_url: description: Provider's token URL. Required when provider is 'generic'. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc scope: description: List of scoped data categories to request in the authentication response. Typically 'email' and 'profile' are the minimum required scopes. However, GitHub requires `user:email', instead and Auth0 requires 'profile', 'email', and 'openid'. global: True forcedType: "[]string" - helpLink: oidc.html + helpLink: oidc pkce: description: Set to 'force' if the OIDC provider does not support auto-detection of PKCE, but does support PKCE. Set to `never` to disable PKCE. The default setting automatically attempts to detect if PKCE is supported. The provider's `well-known/openid-configuration` JSON response must contain the `S256` algorithm within the `code_challenge_methods_supported` list in order for the auto-detection to correctly detect PKCE is supported. global: True forcedType: string - helpLink: oidc.html + helpLink: oidc requested_claims: id_token: email: essential: description: Specifies whether the email claim is necessary. Typically leave this value set to true. + forcedType: bool advanced: True global: True - helpLink: oidc.html + helpLink: oidc files: oidc__jsonnet: title: OIDC Claims Mapping @@ -90,160 +93,169 @@ kratos: advanced: True file: True global: True - helpLink: oidc.html + helpLink: oidc config: session: lifespan: description: Defines the length of a login session. global: True - helpLink: kratos.html + helpLink: kratos whoami: required_aal: description: Sets the Authenticator Assurance Level. Leave as default to ensure proper security protections remain in place. global: True advanced: True - helpLink: kratos.html + helpLink: kratos selfservice: methods: password: - enabled: + enabled: description: Set to True to enable traditional password authentication to SOC. Typically set to true, except when exclusively using OIDC authentication. Some external tool interfaces may not be accessible if local password authentication is disabled. + forcedType: bool global: True advanced: True - helpLink: oidc.html + helpLink: oidc config: haveibeenpwned_enabled: description: Set to True to check if a newly chosen password has ever been found in a published list of previously-compromised passwords. Requires outbound Internet connectivity when enabled. + forcedType: bool global: True - helpLink: kratos.html + helpLink: kratos totp: - enabled: + enabled: description: Set to True to enable Time-based One-Time Password (TOTP) multi-factor authentication (MFA) to SOC. Enable to ensure proper security protections remain in place. Be aware that disabling this setting, after users have already setup TOTP, may prevent users from logging in. + forcedType: bool global: True - helpLink: kratos.html + helpLink: kratos config: issuer: description: The name to show in the MFA authenticator app. Useful for differentiating between installations that share the same user email address. global: True - helpLink: kratos.html + helpLink: kratos webauthn: enabled: description: Set to True to enable Security Keys (WebAuthn / PassKeys) for passwordless or multi-factor authentication (MFA) SOC logins. Security Keys are a Public-Key Infrastructure (PKI) based authentication method, typically involving biometric hardware devices, such as laptop fingerprint scanners and USB hardware keys. Be aware that disabling this setting, after users have already setup their accounts with Security Keys, may prevent users from logging in. + forcedType: bool global: True - helpLink: kratos.html + helpLink: kratos config: - passwordless: + passwordless: description: Set to True to utilize Security Keys (WebAuthn / PassKeys) for passwordless logins. Set to false to utilize Security Keys as a multi-factor authentication (MFA) method supplementing password logins. Be aware that changing this value, after users have already setup their accounts with the previous value, may prevent users from logging in. + forcedType: bool global: True - helpLink: kratos.html + helpLink: kratos rp: id: description: The internal identification used for registering new Security Keys. Leave as default to ensure Security Keys function properly. global: True advanced: True - helpLink: kratos.html + helpLink: kratos origin: description: The URL used to login to SOC. Leave as default to ensure Security Keys function properly. global: True advanced: True - helpLink: kratos.html + helpLink: kratos display_name: description: The name assigned to the security key. Note that URL_BASE is replaced with the hostname or IP address used to login to SOC, to help distinguish multiple Security Onion installations. global: True advanced: True - helpLink: kratos.html + helpLink: kratos flows: settings: privileged_session_max_age: description: The length of time after a successful authentication for a user's session to remain elevated to a privileged session. Privileged sessions are able to change passwords and other security settings for that user. If a session is no longer privileged then the user is redirected to the login form in order to confirm the security change. global: True - helpLink: kratos.html + helpLink: kratos ui_url: description: User accessible URL containing the user self-service profile and security settings. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos required_aal: description: Sets the Authenticator Assurance Level for accessing user self-service profile and security settings. Leave as default to ensure proper security enforcement remains in place. global: True advanced: True - helpLink: kratos.html + helpLink: kratos verification: ui_url: description: User accessible URL containing the Security Onion login page. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos login: ui_url: description: User accessible URL containing the Security Onion login page. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos + lifespan: + description: Defines the duration that a login form will remain valid. + global: True + helpLink: kratos error: ui_url: description: User accessible URL containing the Security Onion login page. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos registration: ui_url: description: User accessible URL containing the Security Onion login page. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos default_browser_return_url: description: Security Onion Console landing page URL. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos allowed_return_urls: description: Internal redirect URL. Leave as default to ensure proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos log: level: description: Log level to use for Kratos logs. global: True - helpLink: kratos.html + helpLink: kratos format: description: Log output format for Kratos logs. global: True - helpLink: kratos.html + helpLink: kratos secrets: default: description: Secret key used for protecting session cookie data. Generated during installation. global: True sensitive: True advanced: True - helpLink: kratos.html + helpLink: kratos serve: public: base_url: description: User accessible URL for authenticating to Kratos. Leave as default for proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos admin: base_url: description: User accessible URL for accessing Kratos administration API. Leave as default for proper operation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos hashers: bcrypt: cost: description: Bcrypt hashing algorithm cost. Higher values consume more CPU and take longer to complete. Actual cost is computed as 2^X where X is the value in this setting. global: True advanced: True - helpLink: kratos.html + helpLink: kratos courier: smtp: connection_uri: description: SMTPS URL for sending outbound account-related emails. Not utilized with the standard Security Onion installation. global: True advanced: True - helpLink: kratos.html + helpLink: kratos diff --git a/salt/logrotate/defaults.yaml b/salt/logrotate/defaults.yaml index 5cb7cf736..2261bb4f7 100644 --- a/salt/logrotate/defaults.yaml +++ b/salt/logrotate/defaults.yaml @@ -180,16 +180,6 @@ logrotate: - extension .log - dateext - dateyesterday - /opt/so/log/stenographer/*_x_log: - - daily - - rotate 14 - - missingok - - copytruncate - - compress - - create - - extension .log - - dateext - - dateyesterday /opt/so/log/salt/so-salt-minion-check: - daily - rotate 14 diff --git a/salt/logrotate/soc_logrotate.yaml b/salt/logrotate/soc_logrotate.yaml index e6bdd596e..f407ab48d 100644 --- a/salt/logrotate/soc_logrotate.yaml +++ b/salt/logrotate/soc_logrotate.yaml @@ -112,13 +112,6 @@ logrotate: multiline: True global: True forcedType: "[]string" - "/opt/so/log/stenographer/*_x_log": - description: List of logrotate options for this file. - title: /opt/so/log/stenographer/*.log - advanced: True - multiline: True - global: True - forcedType: "[]string" "/opt/so/log/salt/so-salt-minion-check": description: List of logrotate options for this file. title: /opt/so/log/salt/so-salt-minion-check diff --git a/salt/logstash/config.sls b/salt/logstash/config.sls index 5a1727e9b..47feba42c 100644 --- a/salt/logstash/config.sls +++ b/salt/logstash/config.sls @@ -10,11 +10,10 @@ {% from 'logstash/map.jinja' import LOGSTASH_MERGED %} {% set ASSIGNED_PIPELINES = LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %} +{% if GLOBALS.role not in ['so-receiver','so-fleet'] %} include: - - ssl - {% if GLOBALS.role not in ['so-receiver','so-fleet'] %} - elasticsearch - {% endif %} +{% endif %} # Create the logstash group logstashgroup: @@ -37,10 +36,6 @@ logstash: - gid: 931 - home: /opt/so/conf/logstash -lslibdir: - file.absent: - - name: /opt/so/conf/logstash/lib - logstash_sbin: file.recurse: - name: /usr/sbin diff --git a/salt/logstash/defaults.yaml b/salt/logstash/defaults.yaml index 5af366459..520182555 100644 --- a/salt/logstash/defaults.yaml +++ b/salt/logstash/defaults.yaml @@ -63,7 +63,7 @@ logstash: settings: lsheap: 500m config: - http_x_host: 0.0.0.0 + api_x_http_x_host: 0.0.0.0 path_x_logs: /var/log/logstash pipeline_x_workers: 1 pipeline_x_batch_x_size: 125 diff --git a/salt/logstash/enabled.sls b/salt/logstash/enabled.sls index cd71cd574..d89304144 100644 --- a/salt/logstash/enabled.sls +++ b/salt/logstash/enabled.sls @@ -6,12 +6,13 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'logstash/map.jinja' import LOGSTASH_MERGED %} {% from 'logstash/map.jinja' import LOGSTASH_NODES %} {% set lsheap = LOGSTASH_MERGED.settings.lsheap %} include: + - ca {% if GLOBALS.role not in ['so-receiver','so-fleet'] %} - elasticsearch.ca {% endif %} @@ -20,9 +21,9 @@ include: - kafka.ca - kafka.ssl {% endif %} + - logstash.ssl - logstash.config - logstash.sostatus - - ssl so-logstash: docker_container.running: @@ -31,7 +32,7 @@ so-logstash: - name: so-logstash - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-logstash'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-logstash'].ip }} - user: logstash - extra_hosts: {% for node in LOGSTASH_NODES %} @@ -39,20 +40,20 @@ so-logstash: - {{hostname}}:{{ip}} {% endfor %} {% endfor %} - {% if DOCKER.containers['so-logstash'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-logstash'].extra_hosts %} + {% if DOCKERMERGED.containers['so-logstash'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-logstash'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - environment: - LS_JAVA_OPTS=-Xms{{ lsheap }} -Xmx{{ lsheap }} - {% if DOCKER.containers['so-logstash'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-logstash'].extra_env %} + {% if DOCKERMERGED.containers['so-logstash'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-logstash'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-logstash'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-logstash'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -65,22 +66,18 @@ so-logstash: - /opt/so/log/logstash:/var/log/logstash:rw - /sys/fs/cgroup:/sys/fs/cgroup:ro - /opt/so/conf/logstash/etc/certs:/usr/share/logstash/certs:ro - {% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} - - /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro - - /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro - {% endif %} + - /etc/pki/tls/certs/intca.crt:/usr/share/filebeat/ca.crt:ro {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %} - /etc/pki/elasticfleet-logstash.crt:/usr/share/logstash/elasticfleet-logstash.crt:ro - /etc/pki/elasticfleet-logstash.key:/usr/share/logstash/elasticfleet-logstash.key:ro - /etc/pki/elasticfleet-lumberjack.crt:/usr/share/logstash/elasticfleet-lumberjack.crt:ro - /etc/pki/elasticfleet-lumberjack.key:/usr/share/logstash/elasticfleet-lumberjack.key:ro + {% if GLOBALS.role != 'so-fleet' %} + - /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro + - /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro + {% endif %} {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %} - - /etc/pki/ca.crt:/usr/share/filebeat/ca.crt:ro - {% else %} - - /etc/pki/tls/certs/intca.crt:/usr/share/filebeat/ca.crt:ro - {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-searchnode' ] %} + {% if GLOBALS.role not in ['so-receiver','so-fleet'] %} - /opt/so/conf/ca/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro - /opt/so/conf/ca/tls-ca-bundle.pem:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro {% endif %} @@ -94,17 +91,34 @@ so-logstash: - /opt/so/log/fleet/:/osquery/logs:ro - /opt/so/log/strelka:/strelka:ro {% endif %} - {% if DOCKER.containers['so-logstash'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-logstash'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-logstash'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-logstash'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-logstash'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-logstash'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-receiver'] %} - - x509: etc_elasticfleet_logstash_key - - x509: etc_elasticfleet_logstash_crt - {% endif %} - file: lsetcsync + - file: trusttheca + {% if GLOBALS.is_manager %} + - file: elasticsearch_cacerts + - file: elasticsearch_capems + {% endif %} + {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %} + - x509: etc_elasticfleet_logstash_crt + - x509: etc_elasticfleet_logstash_key + - x509: etc_elasticfleetlumberjack_crt + - x509: etc_elasticfleetlumberjack_key + {% if GLOBALS.role != 'so-fleet' %} + - x509: etc_filebeat_crt + - file: logstash_filebeat_p8 + {% endif %} + {% endif %} {% for assigned_pipeline in LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %} - file: ls_pipeline_{{assigned_pipeline}} {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} @@ -115,17 +129,20 @@ so-logstash: - file: kafkacertz {% endif %} - require: - {% if grains['role'] in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} + - file: trusttheca + {% if GLOBALS.is_manager %} + - file: elasticsearch_cacerts + - file: elasticsearch_capems + {% endif %} + {% if GLOBALS.is_manager or GLOBALS.role in ['so-fleet', 'so-heavynode', 'so-receiver'] %} + - x509: etc_elasticfleet_logstash_crt + - x509: etc_elasticfleet_logstash_key + - x509: etc_elasticfleetlumberjack_crt + - x509: etc_elasticfleetlumberjack_key + {% if GLOBALS.role != 'so-fleet' %} - x509: etc_filebeat_crt - {% endif %} - {% if grains['role'] in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - {% if grains.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-import'] %} - - file: cacertz - - file: capemz + - file: logstash_filebeat_p8 + {% endif %} {% endif %} {% if GLOBALS.pipeline == 'KAFKA' and GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone', 'so-searchnode'] %} - file: kafkacertz diff --git a/salt/logstash/pipelines/config/so/0011_input_endgame.conf b/salt/logstash/pipelines/config/so/0011_input_endgame.conf index 375585957..c6f9c59e8 100644 --- a/salt/logstash/pipelines/config/so/0011_input_endgame.conf +++ b/salt/logstash/pipelines/config/so/0011_input_endgame.conf @@ -5,10 +5,10 @@ input { codec => es_bulk request_headers_target_field => client_headers remote_host_target_field => client_host - ssl => true + ssl_enabled => true ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"] ssl_certificate => "/usr/share/logstash/filebeat.crt" ssl_key => "/usr/share/logstash/filebeat.key" - ssl_verify_mode => "peer" + ssl_client_authentication => "required" } } diff --git a/salt/logstash/pipelines/config/so/0012_input_elastic_agent.conf.jinja b/salt/logstash/pipelines/config/so/0012_input_elastic_agent.conf.jinja index 6ba29f8e5..a4d699aff 100644 --- a/salt/logstash/pipelines/config/so/0012_input_elastic_agent.conf.jinja +++ b/salt/logstash/pipelines/config/so/0012_input_elastic_agent.conf.jinja @@ -2,11 +2,11 @@ input { elastic_agent { port => 5055 tags => [ "elastic-agent", "input-{{ GLOBALS.hostname }}" ] - ssl => true + ssl_enabled => true ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"] ssl_certificate => "/usr/share/logstash/elasticfleet-logstash.crt" ssl_key => "/usr/share/logstash/elasticfleet-logstash.key" - ssl_verify_mode => "force_peer" + ssl_client_authentication => "required" ecs_compatibility => v8 } } diff --git a/salt/logstash/pipelines/config/so/0013_input_lumberjack_fleet.conf b/salt/logstash/pipelines/config/so/0013_input_lumberjack_fleet.conf index fd9a87a22..b31ffee8d 100644 --- a/salt/logstash/pipelines/config/so/0013_input_lumberjack_fleet.conf +++ b/salt/logstash/pipelines/config/so/0013_input_lumberjack_fleet.conf @@ -2,7 +2,7 @@ input { elastic_agent { port => 5056 tags => [ "elastic-agent", "fleet-lumberjack-input" ] - ssl => true + ssl_enabled => true ssl_certificate => "/usr/share/logstash/elasticfleet-lumberjack.crt" ssl_key => "/usr/share/logstash/elasticfleet-lumberjack.key" ecs_compatibility => v8 diff --git a/salt/logstash/pipelines/config/so/9805_output_elastic_agent.conf.jinja b/salt/logstash/pipelines/config/so/9805_output_elastic_agent.conf.jinja index be7ec6898..4fe138dd8 100644 --- a/salt/logstash/pipelines/config/so/9805_output_elastic_agent.conf.jinja +++ b/salt/logstash/pipelines/config/so/9805_output_elastic_agent.conf.jinja @@ -8,8 +8,8 @@ output { document_id => "%{[metadata][_id]}" index => "so-ip-mappings" silence_errors_in_log => ["version_conflict_engine_exception"] - ssl => true - ssl_certificate_verification => false + ssl_enabled => true + ssl_verification_mode => "none" } } else { @@ -25,8 +25,8 @@ output { document_id => "%{[metadata][_id]}" pipeline => "%{[metadata][pipeline]}" silence_errors_in_log => ["version_conflict_engine_exception"] - ssl => true - ssl_certificate_verification => false + ssl_enabled => true + ssl_verification_mode => "none" } } else { @@ -37,8 +37,8 @@ output { user => "{{ ES_USER }}" password => "{{ ES_PASS }}" pipeline => "%{[metadata][pipeline]}" - ssl => true - ssl_certificate_verification => false + ssl_enabled => true + ssl_verification_mode => "none" } } } @@ -49,8 +49,8 @@ output { data_stream => true user => "{{ ES_USER }}" password => "{{ ES_PASS }}" - ssl => true - ssl_certificate_verification => false + ssl_enabled => true + ssl_verification_mode=> "none" } } } diff --git a/salt/logstash/pipelines/config/so/9900_output_endgame.conf.jinja b/salt/logstash/pipelines/config/so/9900_output_endgame.conf.jinja index c056f5774..27e311fc4 100644 --- a/salt/logstash/pipelines/config/so/9900_output_endgame.conf.jinja +++ b/salt/logstash/pipelines/config/so/9900_output_endgame.conf.jinja @@ -13,8 +13,8 @@ output { user => "{{ ES_USER }}" password => "{{ ES_PASS }}" index => "endgame-%{+YYYY.MM.dd}" - ssl => true - ssl_certificate_verification => false + ssl_enabled => true + ssl_verification_mode => "none" } } } diff --git a/salt/logstash/soc_logstash.yaml b/salt/logstash/soc_logstash.yaml index b617abfdd..5a5816a9e 100644 --- a/salt/logstash/soc_logstash.yaml +++ b/salt/logstash/soc_logstash.yaml @@ -1,13 +1,14 @@ logstash: - enabled: + enabled: description: Enables or disables the Logstash log event forwarding process. On most grid installations, when this process is disabled log events are unable to be ingested into the SOC backend. - helpLink: logstash.html + forcedType: bool + helpLink: logstash assigned_pipelines: roles: standalone: &assigned_pipelines description: List of defined pipelines to add to this role. advanced: True - helpLink: logstash.html + helpLink: logstash multiline: True forcedType: "[]string" duplicates: True @@ -21,7 +22,7 @@ logstash: receiver: &defined_pipelines description: List of pipeline configurations assign to this group. advanced: True - helpLink: logstash.html + helpLink: logstash multiline: True forcedType: "[]string" duplicates: True @@ -39,7 +40,7 @@ logstash: advanced: True multiline: True forcedType: string - helpLink: logstash.html + helpLink: logstash duplicates: True custom002: *pipeline_config custom003: *pipeline_config @@ -53,35 +54,35 @@ logstash: settings: lsheap: description: Heap size to use for logstash - helpLink: logstash.html + helpLink: logstash global: False config: - http_x_host: + api_x_http_x_host: description: Host interface to listen to connections. - helpLink: logstash.html + helpLink: logstash readonly: True advanced: True path_x_logs: description: Path inside the container to wrote logs. - helpLink: logstash.html + helpLink: logstash readonly: True advanced: True pipeline_x_workers: description: Number of worker threads to process events in logstash. - helpLink: logstash.html + helpLink: logstash global: False pipeline_x_batch_x_size: description: Logstash batch size. - helpLink: logstash.html + helpLink: logstash global: False pipeline_x_ecs_compatibility: description: Sets ECS compatibility. This is set per pipeline so you should never need to change this. - helpLink: logstash.html + helpLink: logstash readonly: True advanced: True dmz_nodes: description: "List of receiver nodes in DMZs. Prevents sensors from sending to these receivers. Primarily used for external Elastic agents." - helpLink: logstash.html + helpLink: logstash multiline: True advanced: True forcedType: "[]string" diff --git a/salt/logstash/ssl.sls b/salt/logstash/ssl.sls new file mode 100644 index 000000000..935088e30 --- /dev/null +++ b/salt/logstash/ssl.sls @@ -0,0 +1,287 @@ +# 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 or sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} +{% from 'ca/map.jinja' import CA %} + +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %} + +{% if grains['role'] not in [ 'so-heavynode'] %} +# Start -- Elastic Fleet Logstash Input Cert +etc_elasticfleet_logstash_key: + x509.private_key_managed: + - name: /etc/pki/elasticfleet-logstash.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/elasticfleet-logstash.key') -%} + - prereq: + - x509: etc_elasticfleet_logstash_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +etc_elasticfleet_logstash_crt: + x509.certificate_managed: + - name: /etc/pki/elasticfleet-logstash.crt + - ca_server: {{ CA.server }} + - signing_policy: elasticfleet + - private_key: /etc/pki/elasticfleet-logstash.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }},DNS:{{ GLOBALS.url_base }},IP:{{ GLOBALS.node_ip }}{% if ELASTICFLEETMERGED.config.server.custom_fqdn | length > 0 %},DNS:{{ ELASTICFLEETMERGED.config.server.custom_fqdn | join(',DNS:') }}{% endif %} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + cmd.run: + - name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-logstash.key -topk8 -out /etc/pki/elasticfleet-logstash.p8 -nocrypt" + - onchanges: + - x509: etc_elasticfleet_logstash_key + +eflogstashperms: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-logstash.key + - mode: 640 + - group: 939 + +chownelasticfleetlogstashcrt: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-logstash.crt + - mode: 640 + - user: 931 + - group: 939 + +chownelasticfleetlogstashkey: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-logstash.key + - mode: 640 + - user: 931 + - group: 939 +# End -- Elastic Fleet Logstash Input Cert +{% endif %} # endif is for not including HeavyNodes + +# Start -- Elastic Fleet Node - Logstash Lumberjack Input / Output +# Cert needed on: Managers, Receivers +etc_elasticfleetlumberjack_key: + x509.private_key_managed: + - name: /etc/pki/elasticfleet-lumberjack.key + - bits: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/elasticfleet-lumberjack.key') -%} + - prereq: + - x509: etc_elasticfleetlumberjack_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +etc_elasticfleetlumberjack_crt: + x509.certificate_managed: + - name: /etc/pki/elasticfleet-lumberjack.crt + - ca_server: {{ CA.server }} + - signing_policy: elasticfleet + - private_key: /etc/pki/elasticfleet-lumberjack.key + - CN: {{ GLOBALS.node_ip }} + - subjectAltName: DNS:{{ GLOBALS.hostname }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + cmd.run: + - name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-lumberjack.key -topk8 -out /etc/pki/elasticfleet-lumberjack.p8 -nocrypt" + - onchanges: + - x509: etc_elasticfleetlumberjack_key + +eflogstashlumberjackperms: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-lumberjack.key + - mode: 640 + - group: 939 + +chownilogstashelasticfleetlumberjackp8: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-lumberjack.p8 + - mode: 640 + - user: 931 + - group: 939 + +chownilogstashelasticfleetlogstashlumberjackcrt: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-lumberjack.crt + - mode: 640 + - user: 931 + - group: 939 + +chownilogstashelasticfleetlogstashlumberjackkey: + file.managed: + - replace: False + - name: /etc/pki/elasticfleet-lumberjack.key + - mode: 640 + - user: 931 + - group: 939 +# End -- Elastic Fleet Node - Logstash Lumberjack Input / Output +{% endif %} + +{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-receiver'] %} +etc_filebeat_key: + x509.private_key_managed: + - name: /etc/pki/filebeat.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/filebeat.key') -%} + - prereq: + - x509: etc_filebeat_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +# Request a cert and drop it where it needs to go to be distributed +etc_filebeat_crt: + x509.certificate_managed: + - name: /etc/pki/filebeat.crt + - ca_server: {{ CA.server }} + - signing_policy: filebeat + - private_key: /etc/pki/filebeat.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + cmd.run: + - name: "/usr/bin/openssl pkcs8 -in /etc/pki/filebeat.key -topk8 -out /etc/pki/filebeat.p8 -nocrypt" + - onchanges: + - x509: etc_filebeat_key + +fbperms: + file.managed: + - replace: False + - name: /etc/pki/filebeat.key + - mode: 640 + - group: 939 + +logstash_filebeat_p8: + file.managed: + - replace: False + - name: /etc/pki/filebeat.p8 + - mode: 640 + - user: 931 + - group: 939 + +{% if grains.role not in ['so-heavynode', 'so-receiver'] %} +# Create Symlinks to the keys so I can distribute it to all the things +filebeatdir: + file.directory: + - name: /opt/so/saltstack/local/salt/filebeat/files + - makedirs: True + +fbkeylink: + file.symlink: + - name: /opt/so/saltstack/local/salt/filebeat/files/filebeat.p8 + - target: /etc/pki/filebeat.p8 + - user: socore + - group: socore + +fbcrtlink: + file.symlink: + - name: /opt/so/saltstack/local/salt/filebeat/files/filebeat.crt + - target: /etc/pki/filebeat.crt + - user: socore + - group: socore + +{% endif %} +{% endif %} + +{% if GLOBALS.is_manager or GLOBALS.role in ['so-sensor', 'so-searchnode', 'so-heavynode', 'so-fleet', 'so-idh', 'so-receiver'] %} + +fbcertdir: + file.directory: + - name: /opt/so/conf/filebeat/etc/pki + - makedirs: True + +conf_filebeat_key: + x509.private_key_managed: + - name: /opt/so/conf/filebeat/etc/pki/filebeat.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/opt/so/conf/filebeat/etc/pki/filebeat.key') -%} + - prereq: + - x509: conf_filebeat_crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +# Request a cert and drop it where it needs to go to be distributed +conf_filebeat_crt: + x509.certificate_managed: + - name: /opt/so/conf/filebeat/etc/pki/filebeat.crt + - ca_server: {{ CA.server }} + - signing_policy: filebeat + - private_key: /opt/so/conf/filebeat/etc/pki/filebeat.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + +# Convert the key to pkcs#8 so logstash will work correctly. +filebeatpkcs: + cmd.run: + - name: "/usr/bin/openssl pkcs8 -in /opt/so/conf/filebeat/etc/pki/filebeat.key -topk8 -out /opt/so/conf/filebeat/etc/pki/filebeat.p8 -passout pass:" + - onchanges: + - x509: conf_filebeat_key + +filebeatkeyperms: + file.managed: + - replace: False + - name: /opt/so/conf/filebeat/etc/pki/filebeat.key + - mode: 640 + - group: 939 + +chownfilebeatp8: + file.managed: + - replace: False + - name: /opt/so/conf/filebeat/etc/pki/filebeat.p8 + - mode: 640 + - user: 931 + - group: 939 + +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/manager/elasticsearch.sls b/salt/manager/elasticsearch.sls index ab9dbb287..7731859e3 100644 --- a/salt/manager/elasticsearch.sls +++ b/salt/manager/elasticsearch.sls @@ -1,3 +1,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. + elastic_curl_config_distributed: file.managed: - name: /opt/so/saltstack/local/salt/elasticsearch/curl.config diff --git a/salt/manager/files/mirror.txt b/salt/manager/files/mirror.txt index 732c116b4..a7b906cb7 100644 --- a/salt/manager/files/mirror.txt +++ b/salt/manager/files/mirror.txt @@ -1,2 +1,2 @@ -https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9 -https://repo-alt.securityonion.net/prod/2.4/oracle/9 \ No newline at end of file +https://repo.securityonion.net/file/so-repo/prod/3/oracle/9 +https://repo-alt.securityonion.net/prod/3/oracle/9 \ No newline at end of file diff --git a/salt/manager/init.sls b/salt/manager/init.sls index 7148ea16e..2353bb64b 100644 --- a/salt/manager/init.sls +++ b/salt/manager/init.sls @@ -63,11 +63,9 @@ yara_log_dir: - user - group -{% if GLOBALS.os_family == 'RedHat' %} install_createrepo: pkg.installed: - name: createrepo_c -{% endif %} repo_conf_dir: file.directory: diff --git a/salt/manager/kibana.sls b/salt/manager/kibana.sls index 17ac826c2..8ff876051 100644 --- a/salt/manager/kibana.sls +++ b/salt/manager/kibana.sls @@ -1,3 +1,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. + kibana_curl_config_distributed: file.managed: - name: /opt/so/conf/kibana/curl.config @@ -5,4 +10,4 @@ kibana_curl_config_distributed: - template: jinja - mode: 600 - show_changes: False - - makedirs: True \ No newline at end of file + - makedirs: True diff --git a/salt/manager/managed_soc_annotations.sls b/salt/manager/managed_soc_annotations.sls index 4357b53a2..b2fbb7334 100644 --- a/salt/manager/managed_soc_annotations.sls +++ b/salt/manager/managed_soc_annotations.sls @@ -4,7 +4,7 @@ # Elastic License 2.0. {# Managed elasticsearch/soc_elasticsearch.yaml file for adding integration configuration items to UI #} -{% set managed_integrations = salt['pillar.get']('elasticsearch:managed_integrations', []) %} +{% set managed_integrations = salt['pillar.get']('manager:managed_integrations', []) %} {% if managed_integrations and salt['file.file_exists']('/opt/so/state/esfleet_package_components.json') and salt['file.file_exists']('/opt/so/state/esfleet_component_templates.json') %} {% from 'elasticfleet/integration-defaults.map.jinja' import ADDON_INTEGRATION_DEFAULTS %} {% set addon_integration_keys = ADDON_INTEGRATION_DEFAULTS.keys() %} diff --git a/salt/manager/soc_manager.yaml b/salt/manager/soc_manager.yaml index f0d699f58..78711d782 100644 --- a/salt/manager/soc_manager.yaml +++ b/salt/manager/soc_manager.yaml @@ -2,79 +2,87 @@ manager: reposync: enabled: description: This is the daily task of syncing the Security Onion OS packages. It is recommended that this setting remain enabled to ensure important updates are applied to the grid on an automated, scheduled basis. + forcedType: bool global: True - helpLink: soup.html + helpLink: soup hour: description: The hour of the day in which the repo sync takes place. global: True - helpLink: soup.html + helpLink: soup minute: description: The minute within the hour to run the repo sync. global: True - helpLink: soup.html + helpLink: soup elastalert: description: Enable elastalert 1=enabled 0=disabled. global: True - helpLink: elastalert.html + helpLink: elastalert no_proxy: description: String of hosts to ignore the proxy settings for. global: True - helpLink: proxy.html + helpLink: proxy proxy: description: Proxy server to use for updates. global: True - helpLink: proxy.html + helpLink: proxy additionalCA: description: Additional CA certificates to trust in PEM format. global: True advanced: True multiline: True forcedType: string - helpLink: proxy.html + helpLink: proxy insecureSkipVerify: description: Disable TLS verification for outgoing requests. This will make your installation less secure to MITM attacks. Recommended only for debugging purposes. advanced: True forcedType: bool global: True - helpLink: proxy.html + helpLink: proxy agent_monitoring: enabled: description: Enable monitoring elastic agents for health issues. Can be used to trigger an alert when a 'critical' agent hasn't checked in with fleet for longer than the configured offline threshold. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: bool config: critical_agents: description: List of 'critical' agents to log when they haven't checked in longer than the maximum allowed time. If there are no 'critical' agents specified all offline agents will be logged once they reach the offline threshold. global: True multiline: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: "[]string" custom_kquery: description: For more granular control over what agents to monitor for offline|degraded status add a kquery here. It is recommended to create & test within Elastic Fleet first to ensure your agents are targeted correctly using the query. eg 'status:offline AND tags:INFRA' global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: string advanced: True offline_threshold: description: The maximum allowed time in hours a 'critical' agent has been offline before being logged. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: int realert_threshold: description: The time to pass before another alert for an offline agent exceeding the offline_threshold is generated. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: int page_size: description: The amount of agents that can be processed per API request to fleet. global: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: int advanced: True run_interval: description: The time in minutes between checking fleet agent statuses. global: True advanced: True - helpLink: elastic-fleet.html + helpLink: elastic-fleet forcedType: int + managed_integrations: + description: List of integrations to add into SOC config UI. Enter the full or partial integration name. Eg. 1password, 1pass + forcedType: "[]string" + multiline: True + global: True + advanced: True + helpLink: elasticsearch \ No newline at end of file diff --git a/salt/manager/sync_es_users.sls b/salt/manager/sync_es_users.sls index 5b9fb4efd..29b090e18 100644 --- a/salt/manager/sync_es_users.sls +++ b/salt/manager/sync_es_users.sls @@ -1,3 +1,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. + include: - elasticsearch.auth - kratos diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 51850cd60..f979d7bc0 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -134,8 +134,8 @@ function require() { function verifyEnvironment() { require "jq" require "curl" - response=$(curl -Ss -L ${hydraUrl}/) - [[ "$response" != *"Error 404"* ]] && fail "Unable to communicate with Hydra; specify URL via HYDRA_URL environment variable" + response=$(curl -Ss -L ${hydraUrl}/health/alive) + [[ "$response" != '{"status":"ok"}' ]] && fail "Unable to communicate with Hydra; specify URL via HYDRA_URL environment variable" } function createFile() { diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index abb8f96ec..2d5ef448e 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -462,19 +462,14 @@ function add_sensor_to_minion() { echo " lb_procs: '$CORECOUNT'" echo "suricata:" echo " enabled: True " + echo " pcap:" + echo " enabled: True" if [[ $is_pcaplimit ]]; then - echo " pcap:" echo " maxsize: $MAX_PCAP_SPACE" fi echo " config:" echo " af-packet:" echo " threads: '$CORECOUNT'" - echo "pcap:" - echo " enabled: True" - if [[ $is_pcaplimit ]]; then - echo " config:" - echo " diskfreepercentage: $DFREEPERCENT" - fi echo " " } >> $PILLARFILE if [ $? -ne 0 ]; then @@ -716,6 +711,18 @@ function checkMine() { } } +function create_ca_pillar() { + local capillar=/opt/so/saltstack/local/pillar/ca/init.sls + printf '%s\n'\ + "ca:"\ + " server: $MINION_ID"\ + " " > $capillar + if [ $? -ne 0 ]; then + log "ERROR" "Failed to add $MINION_ID to $capillar" + return 1 + fi +} + function createEVAL() { log "INFO" "Creating EVAL configuration for minion $MINION_ID" is_pcaplimit=true @@ -827,7 +834,6 @@ function createHEAVYNODE() { add_elastic_agent_to_minion || return 1 add_sensor_to_minion || return 1 add_strelka_to_minion || return 1 - add_redis_to_minion || return 1 add_telegraf_to_minion || return 1 } @@ -1013,6 +1019,7 @@ function setupMinionFiles() { managers=("EVAL" "STANDALONE" "IMPORT" "MANAGER" "MANAGERSEARCH") if echo "${managers[@]}" | grep -qw "$NODETYPE"; then add_sensoroni_with_analyze_to_minion || return 1 + create_ca_pillar || return 1 else add_sensoroni_to_minion || return 1 fi diff --git a/salt/manager/tools/sbin/so-saltstack-update b/salt/manager/tools/sbin/so-saltstack-update index 2f385ab89..c8723beb0 100755 --- a/salt/manager/tools/sbin/so-saltstack-update +++ b/salt/manager/tools/sbin/so-saltstack-update @@ -143,7 +143,7 @@ show_usage() { echo " -v Show verbose output (files changed/added/deleted)" echo " -vv Show very verbose output (includes file diffs)" echo " --test Test mode - show what would change without making changes" - echo " branch Git branch to checkout (default: 2.4/main)" + echo " branch Git branch to checkout (default: 3/main)" echo "" echo "Examples:" echo " $0 # Normal operation" @@ -193,7 +193,7 @@ done # Set default branch if not provided if [ -z "$BRANCH" ]; then - BRANCH=2.4/main + BRANCH=3/main fi got_root diff --git a/salt/manager/tools/sbin/so-yaml.py b/salt/manager/tools/sbin/so-yaml.py index 00290f18b..79dcfcac0 100755 --- a/salt/manager/tools/sbin/so-yaml.py +++ b/salt/manager/tools/sbin/so-yaml.py @@ -9,6 +9,7 @@ import os import sys import time import yaml +import json lockFile = "/tmp/so-yaml.lock" @@ -16,19 +17,24 @@ lockFile = "/tmp/so-yaml.lock" def showUsage(args): print('Usage: {} [ARGS...]'.format(sys.argv[0]), file=sys.stderr) print(' General commands:', file=sys.stderr) - print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr) - print(' removelistitem - Remove a list item from a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr) - print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr) - print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr) - print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr) - print(' replace - Replaces (or adds) a new key and set its value. Requires KEY and VALUE args.', file=sys.stderr) - print(' help - Prints this usage information.', file=sys.stderr) + print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr) + print(' appendlistobject - Append an object to a yaml list key. Requires KEY and JSON_OBJECT args.', file=sys.stderr) + print(' removelistitem - Remove a list item from a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr) + print(' replacelistobject - Replace a list object based on a condition. Requires KEY, CONDITION_FIELD, CONDITION_VALUE, and JSON_OBJECT args.', file=sys.stderr) + print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr) + print(' get [-r] - Displays (to stdout) the value stored in the given key. Requires KEY arg. Use -r for raw output without YAML formatting.', file=sys.stderr) + print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr) + print(' replace - Replaces (or adds) a new key and set its value. Requires KEY and VALUE args.', file=sys.stderr) + print(' help - Prints this usage information.', file=sys.stderr) print('', file=sys.stderr) print(' Where:', file=sys.stderr) - print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml', file=sys.stderr) - print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2', file=sys.stderr) - print(' VALUE - Value to set for a given key. Can be a literal value or file: to load from a YAML file.', file=sys.stderr) - print(' LISTITEM - Item to append to a given key\'s list value. Can be a literal value or file: to load from a YAML file.', file=sys.stderr) + print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml', file=sys.stderr) + print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2', file=sys.stderr) + print(' VALUE - Value to set for a given key. Can be a literal value or file: to load from a YAML file.', file=sys.stderr) + print(' LISTITEM - Item to append to a given key\'s list value. Can be a literal value or file: to load from a YAML file.', file=sys.stderr) + print(' JSON_OBJECT - JSON string representing an object to append to a list.', file=sys.stderr) + print(' CONDITION_FIELD - Field name to match in list items (e.g., "name").', file=sys.stderr) + print(' CONDITION_VALUE - Value to match for the condition field.', file=sys.stderr) sys.exit(1) @@ -122,6 +128,52 @@ def append(args): return 0 +def appendListObjectItem(content, key, listObject): + pieces = key.split(".", 1) + if len(pieces) > 1: + appendListObjectItem(content[pieces[0]], pieces[1], listObject) + else: + try: + if not isinstance(content[key], list): + raise AttributeError("Value is not a list") + content[key].append(listObject) + except AttributeError: + print("The existing value for the given key is not a list. No action was taken on the file.", file=sys.stderr) + return 1 + except KeyError: + print("The key provided does not exist. No action was taken on the file.", file=sys.stderr) + return 1 + + +def appendlistobject(args): + if len(args) != 3: + print('Missing filename, key arg, or JSON object to append', file=sys.stderr) + showUsage(None) + return 1 + + filename = args[0] + key = args[1] + jsonString = args[2] + + try: + # Parse the JSON string into a Python dictionary + listObject = json.loads(jsonString) + except json.JSONDecodeError as e: + print(f'Invalid JSON string: {e}', file=sys.stderr) + return 1 + + # Verify that the parsed content is a dictionary (object) + if not isinstance(listObject, dict): + print('The JSON string must represent an object (dictionary), not an array or primitive value.', file=sys.stderr) + return 1 + + content = loadYaml(filename) + appendListObjectItem(content, key, listObject) + writeYaml(filename, content) + + return 0 + + def removelistitem(args): if len(args) != 3: print('Missing filename, key arg, or list item to remove', file=sys.stderr) @@ -139,10 +191,72 @@ def removelistitem(args): return 0 +def replaceListObjectByCondition(content, key, conditionField, conditionValue, newObject): + pieces = key.split(".", 1) + if len(pieces) > 1: + replaceListObjectByCondition(content[pieces[0]], pieces[1], conditionField, conditionValue, newObject) + else: + try: + if not isinstance(content[key], list): + raise AttributeError("Value is not a list") + + # Find and replace the item that matches the condition + found = False + for i, item in enumerate(content[key]): + if isinstance(item, dict) and item.get(conditionField) == conditionValue: + content[key][i] = newObject + found = True + break + + if not found: + print(f"No list item found with {conditionField}={conditionValue}. No action was taken on the file.", file=sys.stderr) + return 1 + + except AttributeError: + print("The existing value for the given key is not a list. No action was taken on the file.", file=sys.stderr) + return 1 + except KeyError: + print("The key provided does not exist. No action was taken on the file.", file=sys.stderr) + return 1 + + +def replacelistobject(args): + if len(args) != 5: + print('Missing filename, key arg, condition field, condition value, or JSON object', file=sys.stderr) + showUsage(None) + return 1 + + filename = args[0] + key = args[1] + conditionField = args[2] + conditionValue = args[3] + jsonString = args[4] + + try: + # Parse the JSON string into a Python dictionary + newObject = json.loads(jsonString) + except json.JSONDecodeError as e: + print(f'Invalid JSON string: {e}', file=sys.stderr) + return 1 + + # Verify that the parsed content is a dictionary (object) + if not isinstance(newObject, dict): + print('The JSON string must represent an object (dictionary), not an array or primitive value.', file=sys.stderr) + return 1 + + content = loadYaml(filename) + result = replaceListObjectByCondition(content, key, conditionField, conditionValue, newObject) + + if result != 1: + writeYaml(filename, content) + + return result if result is not None else 0 + + def addKey(content, key, value): pieces = key.split(".", 1) if len(pieces) > 1: - if not pieces[0] in content: + if pieces[0] not in content or content[pieces[0]] is None: content[pieces[0]] = {} addKey(content[pieces[0]], pieces[1], value) elif key in content: @@ -218,6 +332,11 @@ def getKeyValue(content, key): def get(args): + raw = False + if len(args) > 0 and args[0] == '-r': + raw = True + args = args[1:] + if len(args) != 2: print('Missing filename or key arg', file=sys.stderr) showUsage(None) @@ -229,10 +348,18 @@ def get(args): content = loadYaml(filename) output = getKeyValue(content, key) if output is None: - print("Not found", file=sys.stderr) + print(f"Key '{key}' not found by so-yaml.py", file=sys.stderr) return 2 - print(yaml.safe_dump(output)) + if raw: + if isinstance(output, bool): + print(str(output).lower()) + elif isinstance(output, (dict, list)): + print(yaml.safe_dump(output).strip()) + else: + print(output) + else: + print(yaml.safe_dump(output)) return 0 @@ -247,7 +374,9 @@ def main(): "help": showUsage, "add": add, "append": append, + "appendlistobject": appendlistobject, "removelistitem": removelistitem, + "replacelistobject": replacelistobject, "get": get, "remove": remove, "replace": replace, diff --git a/salt/manager/tools/sbin/so-yaml_test.py b/salt/manager/tools/sbin/so-yaml_test.py index 3b5ec498e..2da8a0be9 100644 --- a/salt/manager/tools/sbin/so-yaml_test.py +++ b/salt/manager/tools/sbin/so-yaml_test.py @@ -395,6 +395,17 @@ class TestRemove(unittest.TestCase): self.assertEqual(result, 0) self.assertIn("45\n...", mock_stdout.getvalue()) + def test_get_int_raw(self): + with patch('sys.stdout', new=StringIO()) as mock_stdout: + filename = "/tmp/so-yaml_test-get.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45 } }, key2: false, key3: [e,f,g]}") + file.close() + + result = soyaml.get(["-r", filename, "key1.child2.deep1"]) + self.assertEqual(result, 0) + self.assertEqual("45\n", mock_stdout.getvalue()) + def test_get_str(self): with patch('sys.stdout', new=StringIO()) as mock_stdout: filename = "/tmp/so-yaml_test-get.yaml" @@ -406,6 +417,51 @@ class TestRemove(unittest.TestCase): self.assertEqual(result, 0) self.assertIn("hello\n...", mock_stdout.getvalue()) + def test_get_str_raw(self): + with patch('sys.stdout', new=StringIO()) as mock_stdout: + filename = "/tmp/so-yaml_test-get.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: \"hello\" } }, key2: false, key3: [e,f,g]}") + file.close() + + result = soyaml.get(["-r", filename, "key1.child2.deep1"]) + self.assertEqual(result, 0) + self.assertEqual("hello\n", mock_stdout.getvalue()) + + def test_get_bool(self): + with patch('sys.stdout', new=StringIO()) as mock_stdout: + filename = "/tmp/so-yaml_test-get.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45 } }, key2: false, key3: [e,f,g]}") + file.close() + + result = soyaml.get([filename, "key2"]) + self.assertEqual(result, 0) + self.assertIn("false\n...", mock_stdout.getvalue()) + + def test_get_bool_raw(self): + with patch('sys.stdout', new=StringIO()) as mock_stdout: + filename = "/tmp/so-yaml_test-get.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45 } }, key2: false, key3: [e,f,g]}") + file.close() + + result = soyaml.get(["-r", filename, "key2"]) + self.assertEqual(result, 0) + self.assertEqual("false\n", mock_stdout.getvalue()) + + def test_get_dict_raw(self): + with patch('sys.stdout', new=StringIO()) as mock_stdout: + filename = "/tmp/so-yaml_test-get.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45 } }, key2: false, key3: [e,f,g]}") + file.close() + + result = soyaml.get(["-r", filename, "key1"]) + self.assertEqual(result, 0) + self.assertIn("child1: 123", mock_stdout.getvalue()) + self.assertNotIn("...", mock_stdout.getvalue()) + def test_get_list(self): with patch('sys.stdout', new=StringIO()) as mock_stdout: filename = "/tmp/so-yaml_test-get.yaml" @@ -580,3 +636,340 @@ class TestRemoveListItem(unittest.TestCase): soyaml.main() sysmock.assert_called() self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue()) + + +class TestAppendListObject(unittest.TestCase): + + def test_appendlistobject_missing_arg(self): + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "help"] + soyaml.appendlistobject(["file", "key"]) + sysmock.assert_called() + self.assertIn("Missing filename, key arg, or JSON object to append", mock_stderr.getvalue()) + + def test_appendlistobject(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123 }, key2: [{name: item1, value: 10}]}") + file.close() + + json_obj = '{"name": "item2", "value": 20}' + soyaml.appendlistobject([filename, "key2", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n child1: 123\nkey2:\n- name: item1\n value: 10\n- name: item2\n value: 20\n" + self.assertEqual(actual, expected) + + def test_appendlistobject_nested(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: [{name: a, id: 1}], child2: abc }, key2: false}") + file.close() + + json_obj = '{"name": "b", "id": 2}' + soyaml.appendlistobject([filename, "key1.child1", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + # YAML doesn't guarantee key order in dictionaries, so check for content + self.assertIn("child1:", actual) + self.assertIn("name: a", actual) + self.assertIn("id: 1", actual) + self.assertIn("name: b", actual) + self.assertIn("id: 2", actual) + self.assertIn("child2: abc", actual) + self.assertIn("key2: false", actual) + + def test_appendlistobject_nested_deep(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [{x: 1}] } }, key2: false}") + file.close() + + json_obj = '{"x": 2, "y": 3}' + soyaml.appendlistobject([filename, "key1.child2.deep2", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2:\n - x: 1\n - x: 2\n y: 3\nkey2: false\n" + self.assertEqual(actual, expected) + + def test_appendlistobject_invalid_json(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.stderr', new=StringIO()) as mock_stderr: + result = soyaml.appendlistobject([filename, "key1", "{invalid json"]) + self.assertEqual(result, 1) + self.assertIn("Invalid JSON string:", mock_stderr.getvalue()) + + def test_appendlistobject_not_dict(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.stderr', new=StringIO()) as mock_stderr: + # Try to append an array instead of an object + result = soyaml.appendlistobject([filename, "key1", "[1, 2, 3]"]) + self.assertEqual(result, 1) + self.assertIn("The JSON string must represent an object (dictionary)", mock_stderr.getvalue()) + + def test_appendlistobject_not_dict_primitive(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.stderr', new=StringIO()) as mock_stderr: + # Try to append a primitive value + result = soyaml.appendlistobject([filename, "key1", "123"]) + self.assertEqual(result, 1) + self.assertIn("The JSON string must represent an object (dictionary)", mock_stderr.getvalue()) + + def test_appendlistobject_key_noexist(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "appendlistobject", filename, "key2", '{"name": "item2"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_appendlistobject_key_noexist_deep(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: [{name: a}] }}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "appendlistobject", filename, "key1.child2", '{"name": "b"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_appendlistobject_key_nonlist(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123 }}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "appendlistobject", filename, "key1", '{"name": "item"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_appendlistobject_key_nonlist_deep(self): + filename = "/tmp/so-yaml_test-appendlistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45 } }}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "appendlistobject", filename, "key1.child2.deep1", '{"name": "item"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue()) + + +class TestReplaceListObject(unittest.TestCase): + + def test_replacelistobject_missing_arg(self): + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "help"] + soyaml.replacelistobject(["file", "key", "field"]) + sysmock.assert_called() + self.assertIn("Missing filename, key arg, condition field, condition value, or JSON object", mock_stderr.getvalue()) + + def test_replacelistobject(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1, value: 10}, {name: item2, value: 20}]}") + file.close() + + json_obj = '{"name": "item2", "value": 25, "extra": "field"}' + soyaml.replacelistobject([filename, "key1", "name", "item2", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n- name: item1\n value: 10\n- extra: field\n name: item2\n value: 25\n" + self.assertEqual(actual, expected) + + def test_replacelistobject_nested(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: [{id: '1', status: active}, {id: '2', status: inactive}] }}") + file.close() + + json_obj = '{"id": "2", "status": "active", "updated": true}' + soyaml.replacelistobject([filename, "key1.child1", "id", "2", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n child1:\n - id: '1'\n status: active\n - id: '2'\n status: active\n updated: true\n" + self.assertEqual(actual, expected) + + def test_replacelistobject_nested_deep(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [{name: a, val: 1}, {name: b, val: 2}] } }}") + file.close() + + json_obj = '{"name": "b", "val": 99}' + soyaml.replacelistobject([filename, "key1.child2.deep2", "name", "b", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2:\n - name: a\n val: 1\n - name: b\n val: 99\n" + self.assertEqual(actual, expected) + + def test_replacelistobject_invalid_json(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.stderr', new=StringIO()) as mock_stderr: + result = soyaml.replacelistobject([filename, "key1", "name", "item1", "{invalid json"]) + self.assertEqual(result, 1) + self.assertIn("Invalid JSON string:", mock_stderr.getvalue()) + + def test_replacelistobject_not_dict(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.stderr', new=StringIO()) as mock_stderr: + result = soyaml.replacelistobject([filename, "key1", "name", "item1", "[1, 2, 3]"]) + self.assertEqual(result, 1) + self.assertIn("The JSON string must represent an object (dictionary)", mock_stderr.getvalue()) + + def test_replacelistobject_condition_not_found(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1, value: 10}, {name: item2, value: 20}]}") + file.close() + + with patch('sys.stderr', new=StringIO()) as mock_stderr: + json_obj = '{"name": "item3", "value": 30}' + result = soyaml.replacelistobject([filename, "key1", "name", "item3", json_obj]) + self.assertEqual(result, 1) + self.assertIn("No list item found with name=item3", mock_stderr.getvalue()) + + # Verify file was not modified + file = open(filename, "r") + actual = file.read() + file.close() + self.assertIn("item1", actual) + self.assertIn("item2", actual) + self.assertNotIn("item3", actual) + + def test_replacelistobject_key_noexist(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1}]}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "replacelistobject", filename, "key2", "name", "item1", '{"name": "item2"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_replacelistobject_key_noexist_deep(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: [{name: a}] }}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "replacelistobject", filename, "key1.child2", "name", "a", '{"name": "b"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_replacelistobject_key_nonlist(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123 }}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "replacelistobject", filename, "key1", "name", "item", '{"name": "item"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_replacelistobject_key_nonlist_deep(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: { child1: 123, child2: { deep1: 45 } }}") + file.close() + + with patch('sys.exit', new=MagicMock()) as sysmock: + with patch('sys.stderr', new=StringIO()) as mock_stderr: + sys.argv = ["cmd", "replacelistobject", filename, "key1.child2.deep1", "name", "item", '{"name": "item"}'] + soyaml.main() + sysmock.assert_called() + self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue()) + + def test_replacelistobject_string_condition_value(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{name: item1, value: 10}, {name: item2, value: 20}]}") + file.close() + + json_obj = '{"name": "item1", "value": 15}' + soyaml.replacelistobject([filename, "key1", "name", "item1", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n- name: item1\n value: 15\n- name: item2\n value: 20\n" + self.assertEqual(actual, expected) + + def test_replacelistobject_numeric_condition_value(self): + filename = "/tmp/so-yaml_test-replacelistobject.yaml" + file = open(filename, "w") + file.write("{key1: [{id: '1', status: active}, {id: '2', status: inactive}]}") + file.close() + + json_obj = '{"id": "1", "status": "updated"}' + soyaml.replacelistobject([filename, "key1", "id", "1", json_obj]) + + file = open(filename, "r") + actual = file.read() + file.close() + + expected = "key1:\n- id: '1'\n status: updated\n- id: '2'\n status: inactive\n" + self.assertEqual(actual, expected) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 87de5baf0..064f84286 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -52,7 +52,7 @@ check_err() { ;; 28) echo 'No space left on device' - echo "Likely ran out of space on disk, please review hardware requirements for Security Onion: $DOC_BASE_URL/hardware.html" + echo "Likely ran out of space on disk, please review hardware requirements for Security Onion: $DOC_BASE_URL/hardware" ;; 30) echo 'Read-only file system' @@ -87,6 +87,16 @@ check_err() { 113) echo 'No route to host' ;; + 160) + echo 'Incompatible Elasticsearch upgrade' + ;; + 161) + echo 'Required intermediate Elasticsearch upgrade not complete' + ;; + 170) + echo "Intermediate upgrade completed successfully to $next_step_so_version, but next soup to Security Onion $originally_requested_so_version could not be started automatically." + echo "Start soup again manually to continue the upgrade to Security Onion $originally_requested_so_version." + ;; *) echo 'Unhandled error' echo "$err_msg" @@ -101,14 +111,6 @@ check_err() { } -add_common() { - cp $UPDATE_DIR/salt/common/tools/sbin/so-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/ - cp $UPDATE_DIR/salt/common/tools/sbin/so-image-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/ - salt-call state.apply common queue=True - echo "Run soup one more time" - exit 0 -} - airgap_mounted() { # Let's see if the ISO is already mounted. if [[ -f /tmp/soagupdate/SecurityOnion/VERSION ]]; then @@ -148,7 +150,7 @@ EOF echo "Ensure you verify the ISO that you downloaded." exit 0 else - echo "Device has been mounted!" + echo "Device has been mounted! $(cat /tmp/soagupdate/SecurityOnion/VERSION)" fi else echo "Could not find Security Onion ISO content at ${ISOLOC}" @@ -204,8 +206,6 @@ check_airgap() { fi } -# {% raw %} - check_local_mods() { local salt_local=/opt/so/saltstack/local @@ -233,8 +233,6 @@ check_local_mods() { fi } -# {% endraw %} - check_pillar_items() { local pillar_output=$(salt-call pillar.items -lerror --out=json) @@ -319,21 +317,6 @@ clone_to_tmp() { fi } -disable_logstash_heavynodes() { - c=0 - printf "\nChecking for heavynodes and disabling Logstash if they exist\n" - for file in /opt/so/saltstack/local/pillar/minions/*.sls; do - if [[ "$file" =~ "_heavynode.sls" && ! "$file" =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then - if [ "$c" -eq 0 ]; then - c=$((c + 1)) - FINAL_MESSAGE_QUEUE+=("Logstash has been disabled on all heavynodes. It can be re-enabled via Grid Configuration in SOC.") - fi - echo "Disabling Logstash for: $file" - so-yaml.py replace "$file" logstash.enabled False - fi - done -} - enable_highstate() { echo "Enabling highstate." salt-call state.enable highstate -l info --local @@ -362,7 +345,6 @@ masterlock() { echo "base:" > $TOPFILE echo " $MINIONID:" >> $TOPFILE echo " - ca" >> $TOPFILE - echo " - ssl" >> $TOPFILE echo " - elasticsearch" >> $TOPFILE } @@ -375,59 +357,12 @@ masterunlock() { fi } -phases_pillar_2_4_80() { - echo "Checking if pillar value: elasticsearch.index_settings.global_overrides.index_template.phases exists" - set +e - PHASES=$(so-yaml.py get /opt/so/saltstack/local/pillar/elasticsearch/soc_elasticsearch.sls elasticsearch.index_settings.global_overrides.index_template.phases) - case $? in - 0) - so-yaml.py remove /opt/so/saltstack/local/pillar/elasticsearch/soc_elasticsearch.sls elasticsearch.index_settings.global_overrides.index_template.phases - read -r -d '' msg <<- EOF -Found elasticsearch.index_settings.global_overrides.index_template.phases was set to: -${PHASES} - -Removed unused pillar value: elasticsearch.index_settings.global_overrides.index_template.phases -To set policies, navigate to the SOC Grid Configuration UI at elasticsearch.index_settings.global_overrides.policy.phases -A backup of all pillar files was saved to /nsm/backup/ -EOF - FINAL_MESSAGE_QUEUE+=("$msg") - ;; - 2) echo "Pillar elasticsearch.index_settings.global_overrides.index_template.phases does not exist. No action taken." ;; - *) echo "so-yaml.py returned something other than 0 or 2 exit code" ;; # we shouldn't see this - esac - set -e -} preupgrade_changes() { # This function is to add any new pillar items if needed. echo "Checking to see if changes are needed." - [[ "$INSTALLEDVERSION" == 2.4.2 ]] && up_to_2.4.3 - [[ "$INSTALLEDVERSION" == 2.4.3 ]] && up_to_2.4.4 - [[ "$INSTALLEDVERSION" == 2.4.4 ]] && up_to_2.4.5 - [[ "$INSTALLEDVERSION" == 2.4.5 ]] && up_to_2.4.10 - [[ "$INSTALLEDVERSION" == 2.4.10 ]] && up_to_2.4.20 - [[ "$INSTALLEDVERSION" == 2.4.20 ]] && up_to_2.4.30 - [[ "$INSTALLEDVERSION" == 2.4.30 ]] && up_to_2.4.40 - [[ "$INSTALLEDVERSION" == 2.4.40 ]] && up_to_2.4.50 - [[ "$INSTALLEDVERSION" == 2.4.50 ]] && up_to_2.4.60 - [[ "$INSTALLEDVERSION" == 2.4.60 ]] && up_to_2.4.70 - [[ "$INSTALLEDVERSION" == 2.4.70 ]] && up_to_2.4.80 - [[ "$INSTALLEDVERSION" == 2.4.80 ]] && up_to_2.4.90 - [[ "$INSTALLEDVERSION" == 2.4.90 ]] && up_to_2.4.100 - [[ "$INSTALLEDVERSION" == 2.4.100 ]] && up_to_2.4.110 - [[ "$INSTALLEDVERSION" == 2.4.110 ]] && up_to_2.4.111 - [[ "$INSTALLEDVERSION" == 2.4.111 ]] && up_to_2.4.120 - [[ "$INSTALLEDVERSION" == 2.4.120 ]] && up_to_2.4.130 - [[ "$INSTALLEDVERSION" == 2.4.130 ]] && up_to_2.4.140 - [[ "$INSTALLEDVERSION" == 2.4.140 ]] && up_to_2.4.141 - [[ "$INSTALLEDVERSION" == 2.4.141 ]] && up_to_2.4.150 - [[ "$INSTALLEDVERSION" == 2.4.150 ]] && up_to_2.4.160 - [[ "$INSTALLEDVERSION" == 2.4.160 ]] && up_to_2.4.170 - [[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180 - [[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190 - [[ "$INSTALLEDVERSION" == 2.4.190 ]] && up_to_2.4.200 - [[ "$INSTALLEDVERSION" == 2.4.200 ]] && up_to_2.4.201 + [[ "$INSTALLEDVERSION" =~ ^2\.4\.21[0-9]+$ ]] && up_to_3.0.0 true } @@ -435,222 +370,104 @@ postupgrade_changes() { # This function is to add any new pillar items if needed. echo "Running post upgrade processes." - [[ "$POSTVERSION" == 2.4.2 ]] && post_to_2.4.3 - [[ "$POSTVERSION" == 2.4.3 ]] && post_to_2.4.4 - [[ "$POSTVERSION" == 2.4.4 ]] && post_to_2.4.5 - [[ "$POSTVERSION" == 2.4.5 ]] && post_to_2.4.10 - [[ "$POSTVERSION" == 2.4.10 ]] && post_to_2.4.20 - [[ "$POSTVERSION" == 2.4.20 ]] && post_to_2.4.30 - [[ "$POSTVERSION" == 2.4.30 ]] && post_to_2.4.40 - [[ "$POSTVERSION" == 2.4.40 ]] && post_to_2.4.50 - [[ "$POSTVERSION" == 2.4.50 ]] && post_to_2.4.60 - [[ "$POSTVERSION" == 2.4.60 ]] && post_to_2.4.70 - [[ "$POSTVERSION" == 2.4.70 ]] && post_to_2.4.80 - [[ "$POSTVERSION" == 2.4.80 ]] && post_to_2.4.90 - [[ "$POSTVERSION" == 2.4.90 ]] && post_to_2.4.100 - [[ "$POSTVERSION" == 2.4.100 ]] && post_to_2.4.110 - [[ "$POSTVERSION" == 2.4.110 ]] && post_to_2.4.111 - [[ "$POSTVERSION" == 2.4.111 ]] && post_to_2.4.120 - [[ "$POSTVERSION" == 2.4.120 ]] && post_to_2.4.130 - [[ "$POSTVERSION" == 2.4.130 ]] && post_to_2.4.140 - [[ "$POSTVERSION" == 2.4.140 ]] && post_to_2.4.141 - [[ "$POSTVERSION" == 2.4.141 ]] && post_to_2.4.150 - [[ "$POSTVERSION" == 2.4.150 ]] && post_to_2.4.160 - [[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170 - [[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180 - [[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190 - [[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200 - [[ "$POSTVERSION" == 2.4.200 ]] && post_to_2.4.201 + [[ "$POSTVERSION" =~ ^2\.4\.21[0-9]+$ ]] && post_to_3.0.0 true } -post_to_2.4.3() { - echo "Nothing to apply" - POSTVERSION=2.4.3 +check_minimum_version() { + if [[ ! "$INSTALLEDVERSION" =~ ^(2\.4\.21[0-9]+|3\.) ]]; then + echo "You must be on at least Security Onion 2.4.210 to upgrade. Currently installed version: $INSTALLEDVERSION" + exit 1 + fi } -post_to_2.4.4() { - echo "Nothing to apply" - POSTVERSION=2.4.4 -} +### 3.0.0 Scripts ### -post_to_2.4.5() { - echo "Nothing to apply" - POSTVERSION=2.4.5 -} +convert_suricata_yes_no() { + echo "Starting suricata yes/no values to true/false conversion." + local SURICATA_FILE=/opt/so/saltstack/local/pillar/suricata/soc_suricata.sls + local MINIONDIR=/opt/so/saltstack/local/pillar/minions + local pillar_files=() -post_to_2.4.10() { - echo "Updating Elastic Fleet ES URLs...." - /sbin/so-elastic-fleet-es-url-update --force - POSTVERSION=2.4.10 -} - -post_to_2.4.20() { - echo "Pruning unused docker volumes on all nodes - This process will run in the background." - salt --async \* cmd.run "docker volume prune -f" - POSTVERSION=2.4.20 -} - -post_to_2.4.30() { - # there is an occasional error with this state: pki_public_ca_crt: TypeError: list indices must be integers or slices, not str - set +e - salt-call state.apply ca queue=True - set -e - stop_salt_minion - mv /etc/pki/managerssl.crt /etc/pki/managerssl.crt.old - mv /etc/pki/managerssl.key /etc/pki/managerssl.key.old - systemctl_func "start" "salt-minion" - salt-call state.apply nginx queue=True - enable_highstate - POSTVERSION=2.4.30 -} - -post_to_2.4.40() { - echo "Nothing to apply" - POSTVERSION=2.4.40 -} - -post_to_2.4.50() { - echo "Nothing to apply" - POSTVERSION=2.4.50 -} - -post_to_2.4.60() { - echo "Nothing to apply" - POSTVERSION=2.4.60 -} - -post_to_2.4.70() { - printf "\nRemoving idh.services from any existing IDH node pillar files\n" - for file in /opt/so/saltstack/local/pillar/minions/*.sls; do - if [[ $file =~ "_idh.sls" && ! $file =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then - echo "Removing idh.services from: $file" - so-yaml.py remove "$file" idh.services - fi + [[ -f "$SURICATA_FILE" ]] && pillar_files+=("$SURICATA_FILE") + for suffix in _eval _heavynode _sensor _standalone; do + for f in "$MINIONDIR"/*${suffix}.sls; do + [[ -f "$f" ]] && pillar_files+=("$f") + done done - POSTVERSION=2.4.70 + + for pillar_file in "${pillar_files[@]}"; do + echo "Checking $pillar_file for suricata yes/no values." + local yaml_output + yaml_output=$(so-yaml.py get -r "$pillar_file" suricata 2>/dev/null) || continue + + local keys_to_fix + keys_to_fix=$(python3 -c " +import yaml, sys +def find(d, prefix=''): + if isinstance(d, dict): + for k, v in d.items(): + path = f'{prefix}.{k}' if prefix else k + if isinstance(v, dict): + find(v, path) + elif isinstance(v, str) and v.lower() in ('yes', 'no'): + print(f'{path} {v.lower()}') +find(yaml.safe_load(sys.stdin) or {}) +" <<< "$yaml_output") || continue + + while IFS=' ' read -r key value; do + [[ -z "$key" ]] && continue + if [[ "$value" == "yes" ]]; then + echo "Replacing suricata.${key} yes -> true in $pillar_file" + so-yaml.py replace "$pillar_file" "suricata.${key}" true + else + echo "Replacing suricata.${key} no -> false in $pillar_file" + so-yaml.py replace "$pillar_file" "suricata.${key}" false + fi + done <<< "$keys_to_fix" + done + echo "Completed suricata yes/no conversion." } -post_to_2.4.80() { - echo -e "\nChecking if update to Elastic Fleet output policy is required\n" - so-kafka-fleet-output-policy - POSTVERSION=2.4.80 +migrate_pcap_to_suricata() { + echo "Starting pillar pcap.enabled to suricata.pcap.enabled migration." + local MINIONDIR=/opt/so/saltstack/local/pillar/minions + local PCAPFILE=/opt/so/saltstack/local/pillar/pcap/soc_pcap.sls + + for pillar_file in "$PCAPFILE" "$MINIONDIR"/*.sls; do + [[ -f "$pillar_file" ]] || continue + pcap_enabled=$(so-yaml.py get -r "$pillar_file" pcap.enabled 2>/dev/null) || continue + echo "Migrating pcap.enabled -> suricata.pcap.enabled in $pillar_file" + so-yaml.py add "$pillar_file" suricata.pcap.enabled "$pcap_enabled" + so-yaml.py remove "$pillar_file" pcap + done + echo "Completed pcap.enabled to suricata.pcap.enabled pillar migration." } -post_to_2.4.90() { - disable_logstash_heavynodes - POSTVERSION=2.4.90 +up_to_3.0.0() { + determine_elastic_agent_upgrade + migrate_pcap_to_suricata + + INSTALLEDVERSION=3.0.0 } -post_to_2.4.100() { - echo "Nothing to apply" - POSTVERSION=2.4.100 +post_to_3.0.0() { + for idx in "logs-idh-so" "logs-redis.log-default"; do + rollover_index "$idx" + done + + # Remove ILM for so-case and so-detection indices + for idx in "so-case" "so-casehistory" "so-detection" "so-detectionhistory"; do + so-elasticsearch-query $idx/_ilm/remove -XPOST + done + + # convert yes/no in suricata pillars to true/false + convert_suricata_yes_no + + POSTVERSION=3.0.0 } -post_to_2.4.110() { - echo "Nothing to apply" - POSTVERSION=2.4.110 -} - -post_to_2.4.111() { - echo "Nothing to apply" - POSTVERSION=2.4.111 -} - -post_to_2.4.120() { - update_elasticsearch_index_settings - - # Manually rollover suricata alerts index to ensure data_stream.dataset expected mapping is set to 'suricata' - rollover_index "logs-suricata.alerts-so" - - POSTVERSION=2.4.120 -} - -post_to_2.4.130() { - # Optional integrations are loaded AFTER initial successful load of core ES templates (/opt/so/state/estemplates.txt) - # Dynamic templates are created in elasticsearch.enabled for every optional integration based on output of so-elastic-fleet-optional-integrations-load script - echo "Ensuring Elasticsearch templates are up to date after updating package registry" - salt-call state.apply elasticsearch queue=True - - # Update kibana default space - salt-call state.apply kibana.config queue=True - echo "Updating Kibana default space" - /usr/sbin/so-kibana-space-defaults - - POSTVERSION=2.4.130 -} - -post_to_2.4.140() { - echo "Nothing to apply" - POSTVERSION=2.4.140 -} - -post_to_2.4.141() { - echo "Nothing to apply" - POSTVERSION=2.4.141 -} - -post_to_2.4.150() { - echo "Nothing to apply" - POSTVERSION=2.4.150 -} - -post_to_2.4.160() { - echo "Nothing to apply" - POSTVERSION=2.4.160 -} - -post_to_2.4.170() { - # Update kibana default space - salt-call state.apply kibana.config queue=True - echo "Updating Kibana default space" - /usr/sbin/so-kibana-space-defaults - - POSTVERSION=2.4.170 -} - -post_to_2.4.180() { - # Force update to Kafka output policy - /usr/sbin/so-kafka-fleet-output-policy --force - - POSTVERSION=2.4.180 -} - -post_to_2.4.190() { - echo "Regenerating Elastic Agent Installers" - /sbin/so-elastic-agent-gen-installers - - # Only need to update import / eval nodes - if [[ "$MINION_ROLE" == "import" ]] || [[ "$MINION_ROLE" == "eval" ]]; then - update_import_fleet_output - fi - - # Check if expected default policy is logstash (global.pipeline is REDIS or "") - pipeline=$(lookup_pillar "pipeline" "global") - if [[ -z "$pipeline" ]] || [[ "$pipeline" == "REDIS" ]]; then - # Check if this grid is currently affected by corrupt fleet output policy - if elastic-agent status | grep "config: key file not configured" > /dev/null 2>&1; then - echo "Elastic Agent shows an ssl error connecting to logstash output. Updating output policy..." - update_default_logstash_output - fi - fi - # Apply new elasticsearch.server index template - rollover_index "logs-elasticsearch.server-default" - - POSTVERSION=2.4.190 -} - -post_to_2.4.200() { - echo "Initiating Suricata idstools migration..." - suricata_idstools_removal_post - - POSTVERSION=2.4.200 -} - -post_to_2.4.201() { - echo "Nothing to apply" - POSTVERSION=2.4.201 -} +### 3.0.0 End ### repo_sync() { echo "Sync the local repo." @@ -702,634 +519,6 @@ stop_salt_minion() { set -e } - -up_to_2.4.3() { - echo "Nothing to do for 2.4.3" - - INSTALLEDVERSION=2.4.3 -} - -up_to_2.4.4() { - echo "Nothing to do for 2.4.4" - - INSTALLEDVERSION=2.4.4 -} - -up_to_2.4.5() { - echo "Nothing to do for 2.4.5" - - INSTALLEDVERSION=2.4.5 -} - -up_to_2.4.10() { - echo "Nothing to do for 2.4.10" - - INSTALLEDVERSION=2.4.10 -} - -up_to_2.4.20() { - echo "Nothing to do for 2.4.20" - - INSTALLEDVERSION=2.4.20 -} - -up_to_2.4.30() { - echo "Nothing to do for 2.4.30" - - INSTALLEDVERSION=2.4.30 -} - -up_to_2.4.40() { - echo "Removing old ATT&CK Navigator Layers..." - rm -f /opt/so/conf/navigator/layers/enterprise-attack.json - rm -f /opt/so/conf/navigator/layers/nav_layer_playbook.json - - INSTALLEDVERSION=2.4.40 -} - -up_to_2.4.50() { - echo "Creating additional pillars.." - mkdir -p /opt/so/saltstack/local/pillar/stig/ - mkdir -p /opt/so/saltstack/local/salt/stig/ - chown socore:socore /opt/so/saltstack/local/salt/stig/ - touch /opt/so/saltstack/local/pillar/stig/adv_stig.sls - touch /opt/so/saltstack/local/pillar/stig/soc_stig.sls - - # the file_roots need to be update due to salt 3006.6 upgrade not allowing symlinks outside the file_roots - # put new so-yaml in place - echo "Updating so-yaml" - \cp -v "$UPDATE_DIR/salt/manager/tools/sbin/so-yaml.py" "$DEFAULT_SALT_DIR/salt/manager/tools/sbin/" - \cp -v "$UPDATE_DIR/salt/manager/tools/sbin/so-yaml.py" /usr/sbin/ - echo "Creating a backup of the salt-master config." - # INSTALLEDVERSION is 2.4.40 at this point, but we want the backup to have the version - # so was at prior to starting upgrade. use POSTVERSION here since it doesnt change until - # post upgrade changes. POSTVERSION set to INSTALLEDVERSION at start of soup - cp -v /etc/salt/master "/etc/salt/master.so-$POSTVERSION.bak" - echo "Adding /opt/so/rules to file_roots in /etc/salt/master using so-yaml" - so-yaml.py append /etc/salt/master file_roots.base /opt/so/rules/nids - echo "Moving Suricata rules" - mkdir /opt/so/rules/nids/suri - chown socore:socore /opt/so/rules/nids/suri - mv -v /opt/so/rules/nids/*.rules /opt/so/rules/nids/suri/. - - echo "Adding /nsm/elastic-fleet/artifacts to file_roots in /etc/salt/master using so-yaml" - so-yaml.py append /etc/salt/master file_roots.base /nsm/elastic-fleet/artifacts - - INSTALLEDVERSION=2.4.50 -} - -up_to_2.4.60() { - echo "Creating directory to store Suricata classification.config" - mkdir -vp /opt/so/saltstack/local/salt/suricata/classification - chown socore:socore /opt/so/saltstack/local/salt/suricata/classification - - INSTALLEDVERSION=2.4.60 -} - -up_to_2.4.70() { - playbook_migration - suricata_idstools_migration - toggle_telemetry - add_detection_test_pillars - - INSTALLEDVERSION=2.4.70 -} - -up_to_2.4.80() { - phases_pillar_2_4_80 - # Kafka configuration changes - - # Global pipeline changes to REDIS or KAFKA - echo "Removing global.pipeline pillar configuration" - sed -i '/pipeline:/d' /opt/so/saltstack/local/pillar/global/soc_global.sls - # Kafka pillars - mkdir -p /opt/so/saltstack/local/pillar/kafka - touch /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - touch /opt/so/saltstack/local/pillar/kafka/adv_kafka.sls - echo 'kafka: ' > /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - kafka_cluster_id=$(get_random_value 22) - echo ' cluster_id: '$kafka_cluster_id >> /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - kafkapass=$(get_random_value) - echo ' password: '$kafkapass >> /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - - INSTALLEDVERSION=2.4.80 -} - -up_to_2.4.90() { - kafkatrust=$(get_random_value) - # rearranging the kafka pillar to reduce clutter in SOC UI - kafkasavedpass=$(so-yaml.py get /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.password) - kafkatrimpass=$(echo "$kafkasavedpass" | sed -n '1 p' ) - echo "Making changes to the Kafka pillar layout" - so-yaml.py remove /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.password - so-yaml.py add /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.config.password "$kafkatrimpass" - so-yaml.py add /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.config.trustpass "$kafkatrust" - - INSTALLEDVERSION=2.4.90 -} - -up_to_2.4.100() { - echo "Nothing to do for 2.4.100" - - INSTALLEDVERSION=2.4.100 -} - -up_to_2.4.110() { - echo "Nothing to do for 2.4.110" - - INSTALLEDVERSION=2.4.110 -} - -up_to_2.4.111() { - echo "Nothing to do for 2.4.111" - - INSTALLEDVERSION=2.4.111 -} - -up_to_2.4.120() { - add_hydra_pillars - - # this is needed for the new versionlock state - mkdir -p /opt/so/saltstack/local/pillar/versionlock - touch /opt/so/saltstack/local/pillar/versionlock/adv_versionlock.sls /opt/so/saltstack/local/pillar/versionlock/soc_versionlock.sls - - - INSTALLEDVERSION=2.4.120 -} - -up_to_2.4.130() { - # Remove any old Elastic Defend config files - rm -f /opt/so/conf/elastic-fleet/integrations/endpoints-initial/elastic-defend-endpoints.json - - # Ensure override exists to allow nmcli access to other devices - touch /etc/NetworkManager/conf.d/10-globally-managed-devices.conf - - INSTALLEDVERSION=2.4.130 -} - -up_to_2.4.140() { - echo "Nothing to do for 2.4.140" - - INSTALLEDVERSION=2.4.140 -} - -up_to_2.4.141() { - echo "Nothing to do for 2.4.141" - - INSTALLEDVERSION=2.4.141 -} - -up_to_2.4.150() { - echo "If the Detection indices exists, update the refresh_interval" - so-elasticsearch-query so-detection*/_settings -X PUT -d '{"index":{"refresh_interval":"1s"}}' - - INSTALLEDVERSION=2.4.150 -} - -up_to_2.4.160() { - echo "Nothing to do for 2.4.160" - - INSTALLEDVERSION=2.4.160 -} - -up_to_2.4.170() { - echo "Creating pillar files for virtualization feature" - - states=("hypervisor" "vm" "libvirt") - - # Create pillar files for each state - for state in "${states[@]}"; do - mkdir -p /opt/so/saltstack/local/pillar/$state - touch /opt/so/saltstack/local/pillar/$state/adv_$state.sls /opt/so/saltstack/local/pillar/$state/soc_$state.sls - done - - - INSTALLEDVERSION=2.4.170 -} - -up_to_2.4.180() { - echo "Nothing to do for 2.4.180" - INSTALLEDVERSION=2.4.180 -} - -up_to_2.4.190() { - # Elastic Update for this release, so download Elastic Agent files - determine_elastic_agent_upgrade - - INSTALLEDVERSION=2.4.190 -} - -up_to_2.4.200() { - echo "Backing up idstools config..." - suricata_idstools_removal_pre - - touch /opt/so/state/esfleet_logstash_config_pillar - - INSTALLEDVERSION=2.4.200 -} - -add_hydra_pillars() { - mkdir -p /opt/so/saltstack/local/pillar/hydra - touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls - chmod 660 /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls - touch /opt/so/saltstack/local/pillar/hydra/adv_hydra.sls - HYDRAKEY=$(get_random_value) - HYDRASALT=$(get_random_value) - printf '%s\n'\ - "hydra:"\ - " config:"\ - " secrets:"\ - " system:"\ - " - '$HYDRAKEY'"\ - " oidc:"\ - " subject_identifiers:"\ - " pairwise:"\ - " salt: '$HYDRASALT'"\ - "" > /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls -} - -add_detection_test_pillars() { - if [[ -n "$SOUP_INTERNAL_TESTING" ]]; then - echo "Adding detection pillar values for automated testing" - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.elastalertengine.allowRegex SecurityOnion - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.elastalertengine.failAfterConsecutiveErrorCount 1 - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.strelkaengine.allowRegex "EquationGroup_Toolset_Apr17__ELV_.*" - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.strelkaengine.failAfterConsecutiveErrorCount 1 - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.suricataengine.allowRegex "(200033\\d|2100538|2102466)" - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.suricataengine.failAfterConsecutiveErrorCount 1 - fi -} - -toggle_telemetry() { - if [[ -z $UNATTENDED && $is_airgap -ne 0 ]]; then - cat << ASSIST_EOF - ---------------- SOC Telemetry --------------- - -The Security Onion development team could use your help! Enabling SOC -Telemetry will help the team understand which UI features are being -used and enables informed prioritization of future development. - -Adjust this setting at anytime via the SOC Configuration screen. - -Documentation: https://docs.securityonion.net/en/2.4/telemetry.html - -ASSIST_EOF - - echo -n "Continue the upgrade with SOC Telemetry enabled [Y/n]? " - - read -r input - input=$(echo "${input,,}" | xargs echo -n) - echo "" - if [[ ${#input} -eq 0 || "$input" == "yes" || "$input" == "y" || "$input" == "yy" ]]; then - echo "Thank you for helping improve Security Onion!" - else - if so-yaml.py replace /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.telemetryEnabled false; then - echo "Disabled SOC Telemetry." - else - fail "Failed to disable SOC Telemetry; aborting." - fi - fi - echo "" - fi -} - -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 -} - -suricata_idstools_migration() { - # For 2.4.70 - - #Backup the pillars for idstools - mkdir -p /nsm/backup/detections-migration/idstools - rsync -av /opt/so/saltstack/local/pillar/idstools/* /nsm/backup/detections-migration/idstools - if [[ $? -eq 0 ]]; then - echo "IDStools configuration has been backed up." - else - fail "Error: rsync failed to copy the files. IDStools configuration has not been backed up." - fi - - #Backup Thresholds - mkdir -p /nsm/backup/detections-migration/suricata - rsync -av /opt/so/saltstack/local/salt/suricata/thresholding /nsm/backup/detections-migration/suricata - if [[ $? -eq 0 ]]; then - echo "Suricata thresholds have been backed up." - else - fail "Error: rsync failed to copy the files. Thresholds have not been backed up." - fi - - #Backup local rules - mkdir -p /nsm/backup/detections-migration/suricata/local-rules - rsync -av /opt/so/rules/nids/suri/local.rules /nsm/backup/detections-migration/suricata/local-rules - if [[ -f /opt/so/saltstack/local/salt/idstools/rules/local.rules ]]; then - rsync -av /opt/so/saltstack/local/salt/idstools/rules/local.rules /nsm/backup/detections-migration/suricata/local-rules/local.rules.bak - fi - - #Tell SOC to migrate - mkdir -p /opt/so/conf/soc/migrations - echo "0" > /opt/so/conf/soc/migrations/suricata-migration-2.4.70 - chown -R socore:socore /opt/so/conf/soc/migrations -} - -playbook_migration() { - # Start SOC Detections migration - mkdir -p /nsm/backup/detections-migration/{suricata,sigma/rules,elastalert} - - # Remove cronjobs - crontab -l | grep -v 'so-playbook-sync_cron' | crontab - - crontab -l | grep -v 'so-playbook-ruleupdate_cron' | crontab - - - if grep -A 1 'playbook:' /opt/so/saltstack/local/pillar/minions/* | grep -q 'enabled: True'; then - - # Check for active Elastalert rules - active_rules_count=$(find /opt/so/rules/elastalert/playbook/ -type f \( -name "*.yaml" -o -name "*.yml" \) | wc -l) - - if [[ "$active_rules_count" -gt 0 ]]; then - # Prompt the user to press ENTER if active Elastalert rules found - echo - echo "$active_rules_count Active Elastalert/Playbook rules found." - echo "In preparation for the new Detections module, they will be backed up and then disabled." - echo - echo "Press ENTER to proceed." - echo - # Read user input - read -r - - echo "Backing up the Elastalert rules..." - rsync -av --ignore-missing-args --stats /opt/so/rules/elastalert/playbook/*.{yaml,yml} /nsm/backup/detections-migration/elastalert/ - - # Verify that rsync completed successfully - if [[ $? -eq 0 ]]; then - # Delete the Elastlaert rules - rm -f /opt/so/rules/elastalert/playbook/*.yaml - echo "Active Elastalert rules have been backed up." - else - fail "Error: rsync failed to copy the files. Active Elastalert rules have not been backed up." - fi - fi - - echo - echo "Exporting Sigma rules from Playbook..." - MYSQLPW=$(awk '/mysql:/ {print $2}' /opt/so/saltstack/local/pillar/secrets.sls) - - docker exec so-mysql sh -c "exec mysql -uroot -p${MYSQLPW} -D playbook -sN -e \"SELECT id, value FROM custom_values WHERE value LIKE '%View Sigma%'\"" | while read -r id value; do - echo -e "$value" > "/nsm/backup/detections-migration/sigma/rules/$id.yaml" - done || fail "Failed to export Sigma rules..." - - echo - echo "Exporting Sigma Filters from Playbook..." - docker exec so-mysql sh -c "exec mysql -uroot -p${MYSQLPW} -D playbook -sN -e \"SELECT issues.subject as title, custom_values.value as filter FROM issues JOIN custom_values ON issues.id = custom_values.customized_id WHERE custom_values.value LIKE '%sofilter%'\"" > /nsm/backup/detections-migration/sigma/custom-filters.txt || fail "Failed to export Custom Sigma Filters." - - echo - echo "Backing up Playbook database..." - docker exec so-mysql sh -c "mysqldump -uroot -p${MYSQLPW} --databases playbook > /tmp/playbook-dump" || fail "Failed to dump Playbook database." - docker cp so-mysql:/tmp/playbook-dump /nsm/backup/detections-migration/sigma/playbook-dump.sql || fail "Failed to backup Playbook database." - fi - - echo - echo "Stopping Playbook services & cleaning up..." - for container in so-playbook so-mysql so-soctopus; do - if [ -n "$(docker ps -q -f name=^${container}$)" ]; then - docker stop $container - fi - done - sed -i '/so-playbook\|so-soctopus\|so-mysql/d' /opt/so/conf/so-status/so-status.conf - rm -f /usr/sbin/so-playbook-* /usr/sbin/so-soctopus-* /usr/sbin/so-mysql-* - - echo - echo "Playbook Migration is complete...." -} - -suricata_idstools_removal_pre() { -# For SOUPs beginning with 2.4.200 - pre SOUP checks - -# Create syncBlock file -install -d -o 939 -g 939 -m 755 /opt/so/conf/soc/fingerprints -install -o 939 -g 939 -m 644 /dev/null /opt/so/conf/soc/fingerprints/suricataengine.syncBlock -cat > /opt/so/conf/soc/fingerprints/suricataengine.syncBlock << EOF -Suricata ruleset sync is blocked until this file is removed. **CRITICAL** Make sure that you have manually added any custom Suricata rulesets via SOC config before removing this file - review the documentation for more details: https://docs.securityonion.net/en/2.4/nids.html#sync-block -EOF - -# Remove possible symlink & create salt local rules dir -[ -L /opt/so/saltstack/local/salt/suricata/rules ] && rm -f /opt/so/saltstack/local/salt/suricata/rules -install -d -o 939 -g 939 /opt/so/saltstack/local/salt/suricata/rules/ || echo "Failed to create Suricata local rules directory" - -# Backup custom rules & overrides -mkdir -p /nsm/backup/detections-migration/2-4-200 -cp /usr/sbin/so-rule-update /nsm/backup/detections-migration/2-4-200 -cp /opt/so/conf/idstools/etc/rulecat.conf /nsm/backup/detections-migration/2-4-200 - -# Backup so-detection index via reindex -echo "Creating sos-backup index template..." -template_result=$(/sbin/so-elasticsearch-query '_index_template/sos-backup' -X PUT \ - --retry 5 --retry-delay 15 --retry-all-errors \ - -d '{"index_patterns":["sos-backup-*"],"priority":501,"template":{"settings":{"index":{"number_of_replicas":0,"number_of_shards":1}}}}') - -if [[ -z "$template_result" ]] || ! echo "$template_result" | jq -e '.acknowledged == true' > /dev/null 2>&1; then - echo "Error: Failed to create sos-backup index template" - echo "$template_result" - exit 1 -fi - -BACKUP_INDEX="sos-backup-detection-$(date +%Y%m%d-%H%M%S)" -echo "Backing up so-detection index to $BACKUP_INDEX..." -reindex_result=$(/sbin/so-elasticsearch-query '_reindex?wait_for_completion=true' \ - --retry 5 --retry-delay 15 --retry-all-errors \ - -X POST -d "{\"source\": {\"index\": \"so-detection\"}, \"dest\": {\"index\": \"$BACKUP_INDEX\"}}") - -if [[ -z "$reindex_result" ]]; then - echo "Error: Backup of detections failed - no response from Elasticsearch" - exit 1 -elif echo "$reindex_result" | jq -e '.created >= 0' > /dev/null 2>&1; then - echo "Backup complete: $(echo "$reindex_result" | jq -r '.created') documents copied" -elif echo "$reindex_result" | grep -q "index_not_found_exception"; then - echo "so-detection index does not exist, skipping backup" -else - echo "Error: Backup of detections failed" - echo "$reindex_result" - exit 1 -fi - -} - -suricata_idstools_removal_post() { -# For SOUPs beginning with 2.4.200 - post SOUP checks - -echo "Checking idstools configuration for custom modifications..." - -# Normalize and hash file content for consistent comparison -# Args: $1 - file path -# Outputs: SHA256 hash to stdout -# Returns: 0 on success, 1 on failure -hash_normalized_file() { - local file="$1" - - if [[ ! -r "$file" ]]; then - return 1 - fi - - # Ensure trailing newline for consistent hashing regardless of source file - { sed -E \ - -e 's/^[[:space:]]+//; s/[[:space:]]+$//' \ - -e '/^$/d' \ - -e 's|--url=http://[^:]+:7788|--url=http://MANAGER:7788|' \ - "$file"; echo; } | sed '/^$/d' | sha256sum | awk '{print $1}' -} - -# Known-default hashes for so-rule-update (ETOPEN ruleset) -KNOWN_SO_RULE_UPDATE_HASHES=( - # 2.4.100+ (suricata 7.0.3, non-airgap) - "5fbd067ced86c8ec72ffb7e1798aa624123b536fb9d78f4b3ad8d3b45db1eae7" # 2.4.100-2.4.190 non-Airgap - # 2.4.90+ airgap (same for 2.4.90 and 2.4.100+) - "61f632c55791338c438c071040f1490066769bcce808b595b5cc7974a90e653a" # 2.4.90+ Airgap - # 2.4.90 (suricata 6.0, non-airgap, comment inside proxy block) - "0380ec52a05933244ab0f0bc506576e1d838483647b40612d5fe4b378e47aedd" # 2.4.90 non-Airgap - # 2.4.10-2.4.80 (suricata 6.0, non-airgap, comment outside proxy block) - "b6e4d1b5a78d57880ad038a9cd2cc6978aeb2dd27d48ea1a44dd866a2aee7ff4" # 2.4.10-2.4.80 non-Airgap - # 2.4.10-2.4.80 airgap - "b20146526ace2b142fde4664f1386a9a1defa319b3a1d113600ad33a1b037dad" # 2.4.10-2.4.80 Airgap - # 2.4.5 and earlier (no pidof check, non-airgap) - "d04f5e4015c348133d28a7840839e82d60009781eaaa1c66f7f67747703590dc" # 2.4.5 non-Airgap -) - -# Known-default hashes for rulecat.conf -KNOWN_RULECAT_CONF_HASHES=( - # 2.4.100+ (suricata 7.0.3) - "302e75dca9110807f09ade2eec3be1fcfc8b2bf6cf2252b0269bb72efeefe67e" # 2.4.100-2.4.190 without SURICATA md_engine - "8029b7718c324a9afa06a5cf180afde703da1277af4bdd30310a6cfa3d6398cb" # 2.4.100-2.4.190 with SURICATA md_engine - # 2.4.80-2.4.90 (suricata 6.0, with --suricata-version and --output) - "4d8b318e6950a6f60b02f307cf27c929efd39652990c1bd0c8820aa8a307e1e7" # 2.4.80-2.4.90 without SURICATA md_engine - "a1ddf264c86c4e91c81c5a317f745a19466d4311e4533ec3a3c91fed04c11678" # 2.4.80-2.4.90 with SURICATA md_engine - # 2.4.50-2.4.70 (/suri/ path, no --suricata-version) - "86e3afb8d0f00c62337195602636864c98580a13ca9cc85029661a539deae6ae" # 2.4.50-2.4.70 without SURICATA md_engine - "5a97604ca5b820a10273a2d6546bb5e00c5122ca5a7dfe0ba0bfbce5fc026f4b" # 2.4.50-2.4.70 with SURICATA md_engine - # 2.4.20-2.4.40 (/nids/ path without /suri/) - "d098ea9ecd94b5cca35bf33543f8ea8f48066a0785221fabda7fef43d2462c29" # 2.4.20-2.4.40 without SURICATA md_engine - "9dbc60df22ae20d65738ba42e620392577857038ba92278e23ec182081d191cd" # 2.4.20-2.4.40 with SURICATA md_engine - # 2.4.5-2.4.10 (/sorules/ path for extraction/filters) - "490f6843d9fca759ee74db3ada9c702e2440b8393f2cfaf07bbe41aaa6d955c3" # 2.4.5-2.4.10 with SURICATA md_engine - # Note: 2.4.5-2.4.10 without SURICATA md_engine has same hash as 2.4.20-2.4.40 without SURICATA md_engine -) - -# Check a config file against known hashes -# Args: $1 - file path, $2 - array name of known hashes -check_config_file() { - local file="$1" - local known_hashes_array="$2" - local file_display_name=$(basename "$file") - - if [[ ! -f "$file" ]]; then - echo "Warning: $file not found" - echo "$file_display_name not found - manual verification required" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - return 1 - fi - - echo "Hashing $file..." - local file_hash - if ! file_hash=$(hash_normalized_file "$file"); then - echo "Warning: Could not read $file" - echo "$file_display_name not readable - manual verification required" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - return 1 - fi - - echo " Hash: $file_hash" - - # Check if hash matches any known default - local -n known_hashes=$known_hashes_array - for known_hash in "${known_hashes[@]}"; do - if [[ "$file_hash" == "$known_hash" ]]; then - echo " Matches known default configuration" - return 0 - fi - done - - # No match - custom configuration detected - echo "Does not match known default - custom configuration detected" - echo "Custom $file_display_name detected (hash: $file_hash)" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - - # If this is so-rule-update, check for ETPRO license code and write out to the syncBlock file - # If ETPRO is enabled, the license code already exists in the so-rule-update script, this is just making it easier to migrate - if [[ "$file_display_name" == "so-rule-update" ]]; then - local etpro_code - etpro_code=$(grep -oP '\-\-etpro=\K[0-9a-fA-F]+' "$file" 2>/dev/null) || true - if [[ -n "$etpro_code" ]]; then - echo "ETPRO code found: $etpro_code" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - fi - fi - - return 1 -} - -# Check so-rule-update and rulecat.conf -SO_RULE_UPDATE="/usr/sbin/so-rule-update" -RULECAT_CONF="/opt/so/conf/idstools/etc/rulecat.conf" - -custom_found=0 - -check_config_file "$SO_RULE_UPDATE" "KNOWN_SO_RULE_UPDATE_HASHES" || custom_found=1 -check_config_file "$RULECAT_CONF" "KNOWN_RULECAT_CONF_HASHES" || custom_found=1 - -# Check for ETPRO rules on airgap systems -if [[ $is_airgap -eq 0 ]] && grep -q 'ETPRO ' /nsm/rules/suricata/emerging-all.rules 2>/dev/null; then - echo "ETPRO rules detected on airgap system - custom configuration" - echo "ETPRO rules detected on Airgap in /nsm/rules/suricata/emerging-all.rules" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - custom_found=1 -fi - -# If no custom configs found, remove syncBlock -if [[ $custom_found -eq 0 ]]; then - echo "idstools migration completed successfully - removing Suricata engine syncBlock" - rm -f /opt/so/conf/soc/fingerprints/suricataengine.syncBlock -else - echo "Custom idstools configuration detected - syncBlock remains in place" - echo "Review /opt/so/conf/soc/fingerprints/suricataengine.syncBlock for details" -fi - -echo "Cleaning up idstools" -echo "Stopping and removing the idstools container..." -if [ -n "$(docker ps -q -f name=^so-idstools$)" ]; then - image_name=$(docker ps -a --filter name=^so-idstools$ --format '{{.Image}}' 2>/dev/null || true) - docker stop so-idstools || echo "Warning: failed to stop so-idstools container" - docker rm so-idstools || echo "Warning: failed to remove so-idstools container" - - if [[ -n "$image_name" ]]; then - echo "Removing idstools image: $image_name" - docker rmi "$image_name" || echo "Warning: failed to remove image $image_name" - fi -fi - -echo "Removing idstools symlink and scripts..." -rm -rf /usr/sbin/so-idstools* -sed -i '/^#\?so-idstools$/d' /opt/so/conf/so-status/so-status.conf -crontab -l | grep -v 'so-rule-update' | crontab - - -# Backup the salt master config & manager pillar before editing it -cp /opt/so/saltstack/local/pillar/minions/$MINIONID.sls /nsm/backup/detections-migration/2-4-200/ -cp /etc/salt/master /nsm/backup/detections-migration/2-4-200/ -so-yaml.py remove /opt/so/saltstack/local/pillar/minions/$MINIONID.sls idstools -so-yaml.py removelistitem /etc/salt/master file_roots.base /opt/so/rules/nids - -} - -up_to_2.4.201() { - echo "Nothing to do for 2.4.201" - - INSTALLEDVERSION=2.4.201 -} - determine_elastic_agent_upgrade() { if [[ $is_airgap -eq 0 ]]; then update_elastic_agent_airgap @@ -1396,68 +585,6 @@ update_airgap_repo() { createrepo /nsm/repo } -update_elasticsearch_index_settings() { - # Update managed indices to reflect latest index template - for idx in "so-detection" "so-detectionhistory" "so-case" "so-casehistory"; do - ilm_name=$idx - if [ "$idx" = "so-detectionhistory" ]; then - ilm_name="so-detection" - elif [ "$idx" = "so-casehistory" ]; then - ilm_name="so-case" - fi - JSON_STRING=$( jq -n --arg ILM_NAME "$ilm_name" '{"settings": {"index.auto_expand_replicas":"0-2","index.lifecycle.name":($ILM_NAME + "-logs")}}') - - echo "Checking if index \"$idx\" exists" - exists=$(curl -K /opt/so/conf/elasticsearch/curl.config -s -o /dev/null -w "%{http_code}" -k -L -H "Content-Type: application/json" "https://localhost:9200/$idx") - if [ $exists -eq 200 ]; then - echo "$idx index found..." - echo "Updating $idx index settings" - curl -K /opt/so/conf/elasticsearch/curl.config -s -k -L -H "Content-Type: application/json" "https://localhost:9200/$idx/_settings" -d "$JSON_STRING" -XPUT - echo -e "\n" - else - echo -e "Skipping $idx... index does not exist\n" - fi - done -} - -update_import_fleet_output() { - if output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" --retry 3 --fail 2>/dev/null); then - # Update the current config of so-manager_elasticsearch output policy in place (leaving any customizations like having changed the preset value from 'balanced' to 'performance') - CAFINGERPRINT=$(openssl x509 -in /etc/pki/tls/certs/intca.crt -outform DER | sha256sum | cut -d' ' -f1 | tr '[:lower:]' '[:upper:]') - updated_policy=$(jq --arg CAFINGERPRINT "$CAFINGERPRINT" '.item | (del(.id) | .ca_trusted_fingerprint = $CAFINGERPRINT)' <<< "$output") - if curl -sK /opt/so/conf/elasticsearch/curl.config -L "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" -XPUT -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$updated_policy" --retry 3 --fail 2>/dev/null; then - echo "Successfully updated so-manager_elasticsearch fleet output policy" - else - fail "Failed to update so-manager_elasticsearch fleet output policy" - fi - fi -} - -update_default_logstash_output() { - echo "Updating fleet logstash output policy grid-logstash" - if logstash_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_logstash" --retry 3 --retry-delay 10 --fail 2>/dev/null); then - # Keep already configured hosts for this update, subsequent host updates come from so-elastic-fleet-outputs-update - HOSTS=$(echo "$logstash_policy" | jq -r '.item.hosts') - DEFAULT_ENABLED=$(echo "$logstash_policy" | jq -r '.item.is_default') - DEFAULT_MONITORING_ENABLED=$(echo "$logstash_policy" | jq -r '.item.is_default_monitoring') - LOGSTASHKEY=$(openssl rsa -in /etc/pki/elasticfleet-logstash.key) - LOGSTASHCRT=$(openssl x509 -in /etc/pki/elasticfleet-logstash.crt) - LOGSTASHCA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt) - JSON_STRING=$(jq -n \ - --argjson HOSTS "$HOSTS" \ - --arg DEFAULT_ENABLED "$DEFAULT_ENABLED" \ - --arg DEFAULT_MONITORING_ENABLED "$DEFAULT_MONITORING_ENABLED" \ - --arg LOGSTASHKEY "$LOGSTASHKEY" \ - --arg LOGSTASHCRT "$LOGSTASHCRT" \ - --arg LOGSTASHCA "$LOGSTASHCA" \ - '{"name":"grid-logstash","type":"logstash","hosts": $HOSTS,"is_default": $DEFAULT_ENABLED,"is_default_monitoring": $DEFAULT_MONITORING_ENABLED,"config_yaml":"","ssl":{"certificate": $LOGSTASHCRT,"certificate_authorities":[ $LOGSTASHCA ]},"secrets":{"ssl":{"key": $LOGSTASHKEY }}}') - fi - - if curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_logstash" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --retry 3 --retry-delay 10 --fail; then - echo "Successfully updated grid-logstash fleet output policy" - fi -} - update_salt_mine() { echo "Populating the mine with mine_functions for each host." set +e @@ -1509,78 +636,46 @@ upgrade_check_salt() { upgrade_salt() { echo "Performing upgrade of Salt from $INSTALLEDSALTVERSION to $NEWSALTVERSION." echo "" - # If rhel family - if [[ $is_rpm ]]; then - # Check if salt-cloud is installed - if rpm -q salt-cloud &>/dev/null; then - SALT_CLOUD_INSTALLED=true - fi - # Check if salt-cloud is configured - if [[ -f /etc/salt/cloud.profiles.d/socloud.conf ]]; then - SALT_CLOUD_CONFIGURED=true - fi - - echo "Removing yum versionlock for Salt." - echo "" - yum versionlock delete "salt" - yum versionlock delete "salt-minion" - yum versionlock delete "salt-master" - # Remove salt-cloud versionlock if installed - if [[ $SALT_CLOUD_INSTALLED == true ]]; then - yum versionlock delete "salt-cloud" - fi - echo "Updating Salt packages." - echo "" - set +e - # if oracle run with -r to ignore repos set by bootstrap - if [[ $OS == 'oracle' ]]; then - # Add -L flag only if salt-cloud is already installed - if [[ $SALT_CLOUD_INSTALLED == true ]]; then - run_check_net_err \ - "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -L -F -M stable \"$NEWSALTVERSION\"" \ - "Could not update salt, please check $SOUP_LOG for details." - else - run_check_net_err \ - "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -F -M stable \"$NEWSALTVERSION\"" \ - "Could not update salt, please check $SOUP_LOG for details." - fi - # if another rhel family variant we want to run without -r to allow the bootstrap script to manage repos - else - run_check_net_err \ - "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -F -M stable \"$NEWSALTVERSION\"" \ - "Could not update salt, please check $SOUP_LOG for details." - fi - set -e - echo "Applying yum versionlock for Salt." - echo "" - yum versionlock add "salt-0:$NEWSALTVERSION-0.*" - yum versionlock add "salt-minion-0:$NEWSALTVERSION-0.*" - yum versionlock add "salt-master-0:$NEWSALTVERSION-0.*" - # Add salt-cloud versionlock if installed - if [[ $SALT_CLOUD_INSTALLED == true ]]; then - yum versionlock add "salt-cloud-0:$NEWSALTVERSION-0.*" - fi - # Else do Ubuntu things - elif [[ $is_deb ]]; then - # ensure these files don't exist when upgrading from 3006.9 to 3006.16 - rm -f /etc/apt/keyrings/salt-archive-keyring-2023.pgp /etc/apt/sources.list.d/salt.list - echo "Removing apt hold for Salt." - echo "" - apt-mark unhold "salt-common" - apt-mark unhold "salt-master" - apt-mark unhold "salt-minion" - echo "Updating Salt packages." - echo "" - set +e + # Check if salt-cloud is installed + if rpm -q salt-cloud &>/dev/null; then + SALT_CLOUD_INSTALLED=true + fi + # Check if salt-cloud is configured + if [[ -f /etc/salt/cloud.profiles.d/socloud.conf ]]; then + SALT_CLOUD_CONFIGURED=true + fi + + echo "Removing yum versionlock for Salt." + echo "" + yum versionlock delete "salt" + yum versionlock delete "salt-minion" + yum versionlock delete "salt-master" + # Remove salt-cloud versionlock if installed + if [[ $SALT_CLOUD_INSTALLED == true ]]; then + yum versionlock delete "salt-cloud" + fi + echo "Updating Salt packages." + echo "" + set +e + # Run with -r to ignore repos set by bootstrap + if [[ $SALT_CLOUD_INSTALLED == true ]]; then run_check_net_err \ - "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -F -M stable \"$NEWSALTVERSION\"" \ + "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -L -F -M stable \"$NEWSALTVERSION\"" \ "Could not update salt, please check $SOUP_LOG for details." - set -e - echo "Applying apt hold for Salt." - echo "" - apt-mark hold "salt-common" - apt-mark hold "salt-master" - apt-mark hold "salt-minion" + else + run_check_net_err \ + "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -F -M stable \"$NEWSALTVERSION\"" \ + "Could not update salt, please check $SOUP_LOG for details." + fi + set -e + echo "Applying yum versionlock for Salt." + echo "" + yum versionlock add "salt-0:$NEWSALTVERSION-0.*" + yum versionlock add "salt-minion-0:$NEWSALTVERSION-0.*" + yum versionlock add "salt-master-0:$NEWSALTVERSION-0.*" + # Add salt-cloud versionlock if installed + if [[ $SALT_CLOUD_INSTALLED == true ]]; then + yum versionlock add "salt-cloud-0:$NEWSALTVERSION-0.*" fi echo "Checking if Salt was upgraded." @@ -1625,37 +720,373 @@ verify_latest_update_script() { fi } + +verify_es_version_compatibility() { + + local es_required_version_statefile_base="/opt/so/state/so_es_required_upgrade_version" + local es_verification_script="/tmp/so_intermediate_upgrade_verification.sh" + local is_active_intermediate_upgrade=1 + # supported upgrade paths for SO-ES versions + declare -A es_upgrade_map=( + ["8.18.8"]="9.0.8" + ) + + # Elasticsearch MUST upgrade through these versions + declare -A es_to_so_version=( + ["8.18.8"]="2.4.190-20251024" + ) + + # Get current Elasticsearch version + if es_version_raw=$(so-elasticsearch-query / --fail --retry 5 --retry-delay 10); then + es_version=$(echo "$es_version_raw" | jq -r '.version.number' ) + else + echo "Could not determine current Elasticsearch version to validate compatibility with post soup Elasticsearch version." + + exit 160 + fi + + if ! target_es_version_raw=$(so-yaml.py get $UPDATE_DIR/salt/elasticsearch/defaults.yaml elasticsearch.version); then + # so-yaml.py failed to get the ES version from upgrade versions elasticsearch/defaults.yaml file. Likely they are upgrading to an SO version older than 2.4.110 prior to the ES version pinning and should be OKAY to continue with the upgrade. + + # if so-yaml.py failed to get the ES version AND the version we are upgrading to is newer than 2.4.110 then we should bail + if [[ $(cat $UPDATE_DIR/VERSION | cut -d'.' -f3) > 110 ]]; then + echo "Couldn't determine the target Elasticsearch version (post soup version) to ensure compatibility with current Elasticsearch version. Exiting" + + exit 160 + fi + + # allow upgrade to version < 2.4.110 without checking ES version compatibility + return 0 + else + target_es_version=$(sed -n '1p' <<< "$target_es_version_raw") + fi + + for statefile in "${es_required_version_statefile_base}"-*; do + [[ -f $statefile ]] || continue + + local es_required_version_statefile_value=$(cat "$statefile") + + if [[ "$es_required_version_statefile_value" == "$target_es_version" ]]; then + echo "Intermediate upgrade to ES $target_es_version is in progress. Skipping Elasticsearch version compatibility check." + is_active_intermediate_upgrade=0 + continue + fi + + # use sort to check if es_required_statefile_value is < the current es_version. + if [[ "$(printf '%s\n' $es_required_version_statefile_value $es_version | sort -V | head -n1)" == "$es_required_version_statefile_value" ]]; then + rm -f "$statefile" + continue + fi + + if [[ ! -f "$es_verification_script" ]]; then + create_intermediate_upgrade_verification_script "$es_verification_script" + fi + + echo -e "\n##############################################################################################################################\n" + echo "A previously required intermediate Elasticsearch upgrade was detected. Verifying that all Searchnodes/Heavynodes have successfully upgraded Elasticsearch to $es_required_version_statefile_value before proceeding with soup to avoid potential data loss! This command can take up to an hour to complete." + timeout --foreground 4000 bash "$es_verification_script" "$es_required_version_statefile_value" "$statefile" + if [[ $? -ne 0 ]]; then + echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + echo "A previous required intermediate Elasticsearch upgrade to $es_required_version_statefile_value has yet to successfully complete across the grid. Please allow time for all Searchnodes/Heavynodes to have upgraded Elasticsearch to $es_required_version_statefile_value before running soup again to avoid potential data loss!" + + echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + exit 161 + fi + echo -e "\n##############################################################################################################################\n" + done + + # if current soup is an intermediate upgrade we can skip the upgrade map check below + if [[ $is_active_intermediate_upgrade -eq 0 ]]; then + return 0 + fi + + if [[ " ${es_upgrade_map[$es_version]} " =~ " $target_es_version " || "$es_version" == "$target_es_version" ]]; then + # supported upgrade + return 0 + else + compatible_versions=${es_upgrade_map[$es_version]} + if [[ -z "$compatible_versions" ]]; then + # If current ES version is not explicitly defined in the upgrade map, we know they have an intermediate upgrade to do. + # We default to the lowest ES version defined in es_to_so_version as $first_es_required_version + local first_es_required_version=$(printf '%s\n' "${!es_to_so_version[@]}" | sort -V | head -n1) + next_step_so_version=${es_to_so_version[$first_es_required_version]} + required_es_upgrade_version="$first_es_required_version" + else + next_step_so_version=${es_to_so_version[${compatible_versions##* }]} + required_es_upgrade_version="${compatible_versions##* }" + fi + echo -e "\n##############################################################################################################################\n" + echo -e "You are currently running Security Onion $INSTALLEDVERSION. You will need to update to version $next_step_so_version before updating to $(cat $UPDATE_DIR/VERSION).\n" + + es_required_version_statefile="${es_required_version_statefile_base}-${required_es_upgrade_version}" + echo "$required_es_upgrade_version" > "$es_required_version_statefile" + + # We expect to upgrade to the latest compatiable minor version of ES + create_intermediate_upgrade_verification_script "$es_verification_script" + + if [[ $is_airgap -eq 0 ]]; then + run_airgap_intermediate_upgrade + else + if [[ ! -z $ISOLOC ]]; then + originally_requested_iso_location="$ISOLOC" + fi + # Make sure ISOLOC is not set. Network installs that used soup -f would have ISOLOC set. + unset ISOLOC + + run_network_intermediate_upgrade + fi + fi + +} + +wait_for_salt_minion_with_restart() { + local minion="$1" + local max_wait="${2:-60}" + local interval="${3:-3}" + local logfile="$4" + + wait_for_salt_minion "$minion" "$max_wait" "$interval" "$logfile" + local result=$? + + if [[ $result -ne 0 ]]; then + echo "$(date '+%a %d %b %Y %H:%M:%S.%6N') - salt-minion not ready, attempting restart..." + systemctl_func "restart" "salt-minion" + wait_for_salt_minion "$minion" "$max_wait" "$interval" "$logfile" + result=$? + fi + + return $result +} + +run_airgap_intermediate_upgrade() { + local originally_requested_so_version=$(cat $UPDATE_DIR/VERSION) + # preserve ISOLOC value, so we can try to use it post intermediate upgrade + local originally_requested_iso_location="$ISOLOC" + + # make sure a fresh ISO gets mounted + unmount_update + + echo "You can download the $next_step_so_version ISO image from https://download.securityonion.net/file/securityonion/securityonion-$next_step_so_version.iso" + echo -e "\nIf you have the next ISO / USB ready, enter the path now eg. /dev/sdd, /home/onion/securityonion-$next_step_so_version.iso:" + + while [[ -z "$next_iso_location" ]] || [[ ! -f "$next_iso_location" && ! -b "$next_iso_location" ]]; do + # List removable devices if any are present + local removable_devices=$(lsblk -no PATH,SIZE,TYPE,MOUNTPOINTS,RM | awk '$NF==1') + if [[ -n "$removable_devices" ]]; then + echo "PATH SIZE TYPE MOUNTPOINTS RM" + echo "$removable_devices" + fi + + read -rp "Device/ISO Path (or 'exit' to quit): " next_iso_location + if [[ "${next_iso_location,,}" == "exit" ]]; then + echo "Exiting soup. Before reattempting to upgrade to $originally_requested_so_version, please first upgrade to $next_step_so_version to ensure Elasticsearch can properly update through the required versions." + + exit 160 + fi + + if [[ ! -f "$next_iso_location" && ! -b "$next_iso_location" ]]; then + echo "$next_iso_location is not a valid file or block device." + next_iso_location="" + fi + done + + echo "Using $next_iso_location for required intermediary upgrade." + exec bash < "$verification_script" + #!/bin/bash + + SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE="/root/so_intermediate_upgrade_verification_failures.log" + CURRENT_TIME=$(date +%Y%m%d.%H%M%S) + EXPECTED_ES_VERSION="$1" + + if [[ -z "$EXPECTED_ES_VERSION" ]]; then + echo -e "\nExpected Elasticsearch version not provided. Usage: $0 " + exit 1 + fi + + if [[ -f "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" ]]; then + mv "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE.$CURRENT_TIME" + fi + + check_heavynodes_es_version() { + # Check if heavynodes are in this grid + if ! salt-key -l accepted | grep -q 'heavynode$'; then + + # No heavynodes, skip version check + echo "No heavynodes detected in this Security Onion deployment. Skipping heavynode Elasticsearch version verification." + return 0 + fi + + echo -e "\nOne or more heavynodes detected. Verifying their Elasticsearch versions." + + local retries=20 + local retry_count=0 + local delay=180 + + while [[ $retry_count -lt $retries ]]; do + # keep stderr with variable for logging + heavynode_versions=$(salt -C 'G@role:so-heavynode' cmd.run 'so-elasticsearch-query / --retry 3 --retry-delay 10 | jq ".version.number"' shell=/bin/bash --out=json 2> /dev/null) + local exit_status=$? + + # Check that all heavynodes returned good data + if [[ $exit_status -ne 0 ]]; then + echo "Failed to retrieve Elasticsearch version from one or more heavynodes... Retrying in $delay seconds. Attempt $((retry_count + 1)) of $retries." + ((retry_count++)) + sleep $delay + + continue + else + if echo "$heavynode_versions" | jq -s --arg expected "\"$EXPECTED_ES_VERSION\"" --exit-status 'all(.[]; . | to_entries | all(.[]; .value == $expected))' > /dev/null; then + echo -e "\nAll heavynodes are at the expected Elasticsearch version $EXPECTED_ES_VERSION." + + return 0 + else + echo "One or more heavynodes are not at the expected Elasticsearch version $EXPECTED_ES_VERSION. Rechecking in $delay seconds. Attempt $((retry_count + 1)) of $retries." + ((retry_count++)) + sleep $delay + + continue + fi + fi + done + + echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + echo "One or more heavynodes is not at the expected Elasticsearch version $EXPECTED_ES_VERSION." + echo "Current versions:" + echo "$heavynode_versions" | jq -s 'add' + echo "$heavynode_versions" | jq -s 'add' >> "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" + echo -e "\n Stopping automatic upgrade to latest Security Onion version. Heavynodes must ALL be at Elasticsearch version $EXPECTED_ES_VERSION before proceeding with the next upgrade step to avoid potential data loss!" + echo -e "\n Heavynodes will upgrade themselves to Elasticsearch $EXPECTED_ES_VERSION on their own, but this process can take a long time depending on network link between Manager and Heavynodes." + echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + return 1 + } + + check_searchnodes_es_version() { + local retries=20 + local retry_count=0 + local delay=180 + + while [[ $retry_count -lt $retries ]]; do + # keep stderr with variable for logging + cluster_versions=$(so-elasticsearch-query _nodes/_all/version --retry 5 --retry-delay 10 --fail 2>&1) + local exit_status=$? + + if [[ $exit_status -ne 0 ]]; then + echo "Failed to retrieve Elasticsearch versions from searchnodes... Retrying in $delay seconds. Attempt $((retry_count + 1)) of $retries." + ((retry_count++)) + sleep $delay + + continue + else + if echo "$cluster_versions" | jq --arg expected "$EXPECTED_ES_VERSION" --exit-status '.nodes | to_entries | all(.[].value.version; . == $expected)' > /dev/null; then + echo "All Searchnodes are at the expected Elasticsearch version $EXPECTED_ES_VERSION." + + return 0 + else + echo "One or more Searchnodes is not at the expected Elasticsearch version $EXPECTED_ES_VERSION. Rechecking in $delay seconds. Attempt $((retry_count + 1)) of $retries." + ((retry_count++)) + sleep $delay + + continue + fi + fi + done + + echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + echo "One or more Searchnodes is not at the expected Elasticsearch version $EXPECTED_ES_VERSION." + echo "Current versions:" + echo "$cluster_versions" | jq '.nodes | to_entries | map({(.value.name): .value.version}) | sort | add' + echo "$cluster_versions" >> "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" + echo -e "\nStopping automatic upgrade to latest version. Searchnodes must ALL be at Elasticsearch version $EXPECTED_ES_VERSION before proceeding with the next upgrade step to avoid potential data loss!" + echo -e "\nSearchnodes will upgrade themselves to Elasticsearch $EXPECTED_ES_VERSION on their own, but this process can take a while depending on cluster size / network link between Manager and Searchnodes." + echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + + echo "$cluster_versions" > "$SOUP_INTERMEDIATE_UPGRADE_FAILURES_LOG_FILE" + + return 1 + + } + + # Need to add a check for heavynodes and ensure all heavynodes get their own "cluster" upgraded before moving on to final upgrade. + check_searchnodes_es_version || exit 1 + check_heavynodes_es_version || exit 1 + + # Remove required version state file after successful verification + rm -f "$2" + + exit 0 + +EOF +} + # Keeping this block in case we need to do a hotfix that requires salt update apply_hotfix() { - if [[ "$INSTALLEDVERSION" == "2.4.20" ]] ; then - salt-call state.apply elasticfleet -l info queue=True - . /usr/sbin/so-elastic-fleet-common - elastic_fleet_integration_remove endpoints-initial elastic-defend-endpoints - /usr/sbin/so-elastic-fleet-integration-policy-elastic-defend - elif [[ "$INSTALLEDVERSION" == "2.4.30" ]] ; then - if [[ $is_airgap -eq 0 ]]; then - update_airgap_rules - fi - if [[ -f /etc/pki/managerssl.key.old ]]; then - echo "Skipping Certificate Generation" - else - rm -f /opt/so/conf/elastic-fleet/integrations/endpoints-initial/elastic-defend-endpoints.json - so-kibana-restart --force - so-kibana-api-check - . /usr/sbin/so-elastic-fleet-common - - elastic_fleet_integration_remove endpoints-initial elastic-defend-endpoints - rm -f /opt/so/state/eaintegrations.txt - salt-call state.apply ca queue=True - stop_salt_minion - mv /etc/pki/managerssl.crt /etc/pki/managerssl.crt.old - mv /etc/pki/managerssl.key /etc/pki/managerssl.key.old - systemctl_func "start" "salt-minion" - (wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG" - fi - else echo "No actions required. ($INSTALLEDVERSION/$HOTFIXVERSION)" - fi } failed_soup_restore_items() { @@ -1681,6 +1112,10 @@ main() { echo "" set_os + if [[ ! $is_oracle ]]; then + fail "This OS is not supported. Security Onion requires Oracle Linux 9." + fi + check_salt_master_status 1 || fail "Could not talk to salt master: Please run 'systemctl status salt-master' to ensure the salt-master service is running and check the log at /opt/so/log/salt/master." echo "Checking to see if this is a manager." @@ -1703,6 +1138,8 @@ main() { MINION_ROLE=$(lookup_role) echo "Found that Security Onion $INSTALLEDVERSION is currently installed." echo "" + check_minimum_version + if [[ $is_airgap -eq 0 ]]; then # Let's mount the ISO since this is airgap airgap_mounted @@ -1721,6 +1158,9 @@ main() { echo "Verifying we have the latest soup script." verify_latest_update_script + echo "Verifying Elasticsearch version compatibility before upgrading." + verify_es_version_compatibility + echo "Let's see if we need to update Security Onion." upgrade_check upgrade_space @@ -1770,7 +1210,7 @@ main() { else update_registry set +e - update_docker_containers 'soup' '' '' '/dev/stdout' 2>&1 | tee -a "$SOUP_LOG" + update_docker_containers 'soup' '' '' '/dev/stdout' 2>&1 set -e fi @@ -1785,14 +1225,6 @@ main() { echo "Upgrading Salt" # Update the repo files so it can actually upgrade upgrade_salt - - # for Debian based distro, we need to stop salt again after upgrade output below is from bootstrap-salt - # * WARN: Not starting daemons on Debian based distributions - # is not working mostly because starting them is the default behaviour. - if [[ $is_deb ]]; then - stop_salt_minion - stop_salt_master - fi fi preupgrade_changes @@ -1848,7 +1280,7 @@ main() { echo "" echo "Running a highstate. This could take several minutes." set +e - (wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG" + wait_for_salt_minion_with_restart "$MINIONID" "60" "3" "$SOUP_LOG" || fail "Salt minion was not running or ready." highstate set -e @@ -1861,10 +1293,15 @@ main() { check_saltmaster_status echo "Running a highstate to complete the Security Onion upgrade on this manager. This could take several minutes." - (wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG" + wait_for_salt_minion_with_restart "$MINIONID" "60" "3" "$SOUP_LOG" || fail "Salt minion was not running or ready." # Stop long-running scripts to allow potentially updated scripts to load on the next execution. - killall salt-relay.sh + if pgrep salt-relay.sh > /dev/null 2>&1; then + echo "Stopping salt-relay.sh" + killall salt-relay.sh + else + echo "salt-relay.sh is not running" + fi # ensure the mine is updated and populated before highstates run, following the salt-master restart update_salt_mine @@ -1927,7 +1364,7 @@ Each minion is on a random 15 minute check-in period and things like network ban If it looks like you’re missing data after the upgrade, please avoid restarting services and instead make sure at least one search node has completed its upgrade. The best way to do this is to run 'sudo salt-call state.highstate' from a search node and make sure there are no errors. Typically if it works on one node it will work on the rest. Sensor nodes are less complex and will update as they check in so you can monitor those from the Grid section of SOC. -For more information, please see $DOC_BASE_URL/soup.html#distributed-deployments. +For more information, please see $DOC_BASE_URL/soup#distributed-deployments. EOF @@ -1941,7 +1378,7 @@ EOF A custom Elasticsearch configuration has been found at /opt/so/saltstack/local/elasticsearch/files/elasticsearch.yml. This file is no longer referenced in Security Onion versions >= 2.3.80. -If you still need those customizations, you'll need to manually migrate them to the new Elasticsearch config as shown at $DOC_BASE_URL/elasticsearch.html. +If you still need those customizations, you'll need to manually migrate them to the new Elasticsearch config as shown at $DOC_BASE_URL/elasticsearch. EOF @@ -2002,7 +1439,7 @@ if [[ -z $UNATTENDED ]]; then SOUP - Security Onion UPdater Please review the following for more information about the update process and recent updates: -$DOC_BASE_URL/soup.html +$DOC_BASE_URL/soup https://blog.securityonion.net WARNING: If you run soup via an SSH session and that SSH session terminates, then any processes running in that session would terminate. You should avoid leaving soup unattended especially if the machine you are SSHing from is configured to sleep after a period of time. You might also consider using something like screen or tmux so that if your SSH session terminates, the processes will continue running on the server. diff --git a/salt/nginx/config.sls b/salt/nginx/config.sls index 27611034c..ead3d9986 100644 --- a/salt/nginx/config.sls +++ b/salt/nginx/config.sls @@ -6,9 +6,6 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -include: - - ssl - # Drop the correct nginx config based on role nginxconfdir: file.directory: diff --git a/salt/nginx/defaults.yaml b/salt/nginx/defaults.yaml index 3e36233e7..bae5413a8 100644 --- a/salt/nginx/defaults.yaml +++ b/salt/nginx/defaults.yaml @@ -3,6 +3,7 @@ nginx: external_suricata: False ssl: replace_cert: False + alt_names: [] config: throttle_login_burst: 12 throttle_login_rate: 20 diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls index 4f57063c2..2e4c9631c 100644 --- a/salt/nginx/enabled.sls +++ b/salt/nginx/enabled.sls @@ -6,83 +6,16 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'nginx/map.jinja' import NGINXMERGED %} -{% set ca_server = GLOBALS.minion_id %} include: + - nginx.ssl - nginx.config - nginx.sostatus - -{% if grains.role not in ['so-fleet'] %} - -{# if the user has selected to replace the crt and key in the ui #} -{% if NGINXMERGED.ssl.replace_cert %} - -managerssl_key: - file.managed: - - name: /etc/pki/managerssl.key - - source: salt://nginx/ssl/ssl.key - - mode: 640 - - group: 939 - - watch_in: - - docker_container: so-nginx - -managerssl_crt: - file.managed: - - name: /etc/pki/managerssl.crt - - source: salt://nginx/ssl/ssl.crt - - mode: 644 - - watch_in: - - docker_container: so-nginx - -{% else %} - -managerssl_key: - x509.private_key_managed: - - name: /etc/pki/managerssl.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/managerssl.key') -%} - - prereq: - - x509: /etc/pki/managerssl.crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - - watch_in: - - docker_container: so-nginx - -# Create a cert for the reverse proxy -managerssl_crt: - x509.certificate_managed: - - name: /etc/pki/managerssl.crt - - ca_server: {{ ca_server }} - - signing_policy: managerssl - - private_key: /etc/pki/managerssl.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: "DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }}, DNS:{{ GLOBALS.url_base }}" - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - - watch_in: - - docker_container: so-nginx - -{% endif %} - -msslkeyperms: - file.managed: - - replace: False - - name: /etc/pki/managerssl.key - - mode: 640 - - group: 939 - +{% if GLOBALS.role != 'so-fleet' %} +{% set container_config = 'so-nginx' %} make-rule-dir-nginx: file.directory: - name: /nsm/rules @@ -92,15 +25,11 @@ make-rule-dir-nginx: - user - group - show_changes: False - -{% endif %} -{# if this is an so-fleet node then we want to use the port bindings, custom bind mounts defined for fleet #} -{% if GLOBALS.role == 'so-fleet' %} -{% set container_config = 'so-nginx-fleet-node' %} -{% else %} -{% set container_config = 'so-nginx' %} -{% endif %} +{% else %} +{# if this is an so-fleet node then we want to use the port bindings, custom bind mounts defined for fleet #} +{% set container_config = 'so-nginx-fleet-node' %} +{% endif %} so-nginx: docker_container.running: @@ -108,11 +37,11 @@ so-nginx: - hostname: so-nginx - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers[container_config].ip }} + - ipv4_address: {{ DOCKERMERGED.containers[container_config].ip }} - extra_hosts: - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - {% if DOCKER.containers[container_config].extra_hosts %} - {% for XTRAHOST in DOCKER.containers[container_config].extra_hosts %} + {% if DOCKERMERGED.containers[container_config].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers[container_config].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} @@ -135,37 +64,52 @@ so-nginx: - /opt/so/rules/nids/suri:/surirules:ro {% endif %} {% endif %} - {% if DOCKER.containers[container_config].custom_bind_mounts %} - {% for BIND in DOCKER.containers[container_config].custom_bind_mounts %} + {% if DOCKERMERGED.containers[container_config].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers[container_config].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers[container_config].extra_env %} + {% if DOCKERMERGED.containers[container_config].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers[container_config].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers[container_config].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers[container_config].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers[container_config].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - cap_add: NET_BIND_SERVICE - port_bindings: - {% for BINDING in DOCKER.containers[container_config].port_bindings %} + {% for BINDING in DOCKERMERGED.containers[container_config].port_bindings %} - {{ BINDING }} {% endfor %} - watch: - file: nginxconf - file: nginxconfdir - - require: - - file: nginxconf -{% if GLOBALS.is_manager %} -{% if NGINXMERGED.ssl.replace_cert %} + {% if GLOBALS.is_manager %} + {% if NGINXMERGED.ssl.replace_cert %} - file: managerssl_key - file: managerssl_crt -{% else %} + {% else %} - x509: managerssl_key - x509: managerssl_crt -{% endif%} + {% endif%} + {% endif %} + - require: + - file: nginxconf + {% if GLOBALS.is_manager %} + {% if NGINXMERGED.ssl.replace_cert %} + - file: managerssl_key + - file: managerssl_crt + {% else %} + - x509: managerssl_key + - x509: managerssl_crt + {% endif%} - file: navigatorconfig -{% endif %} + {% endif %} delete_so-nginx_so-status.disabled: file.uncomment: diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index caa05bbff..0c98b7b28 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -1,5 +1,5 @@ {%- from 'vars/globals.map.jinja' import GLOBALS %} -{%- from 'docker/docker.map.jinja' import DOCKER %} +{%- from 'docker/docker.map.jinja' import DOCKERMERGED %} {%- from 'nginx/map.jinja' import NGINXMERGED %} {%- set role = grains.id.split('_') | last %} {%- set influxpass = salt['pillar.get']('secrets:influx_pass') %} @@ -60,6 +60,8 @@ http { {%- endif %} {%- if GLOBALS.is_manager %} + {%- set all_names = [GLOBALS.hostname, GLOBALS.url_base] + NGINXMERGED.ssl.alt_names %} + {%- set full_server_name = all_names | unique | join(' ') %} server { listen 80 default_server; @@ -69,7 +71,7 @@ http { server { listen 8443; - server_name {{ GLOBALS.url_base }}; + server_name {{ full_server_name }}; root /opt/socore/html; location /artifacts/ { try_files $uri =206; @@ -112,7 +114,7 @@ http { server { listen 7788; - server_name {{ GLOBALS.url_base }}; + server_name {{ full_server_name }}; root /nsm/rules; location / { allow all; @@ -128,7 +130,7 @@ http { server { listen 7789 ssl; http2 on; - server_name {{ GLOBALS.url_base }}; + server_name {{ full_server_name }}; root /surirules; add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval' https: data: blob: wss:; frame-ancestors 'self'"; @@ -161,7 +163,7 @@ http { server { listen 443 ssl; http2 on; - server_name {{ GLOBALS.url_base }}; + server_name {{ full_server_name }}; root /opt/socore/html; index index.html; @@ -181,7 +183,7 @@ http { ssl_prefer_server_ciphers on; ssl_protocols TLSv1.2 TLSv1.3; - location ~* (^/login/.*|^/js/.*|^/css/.*|^/images/.*) { + location ~* (^/login/.*|^/js/.*|^/css/.*|^/images/.*|^/pages/.*|^/docs/.*) { proxy_pass http://{{ GLOBALS.manager }}:9822; proxy_read_timeout 90; proxy_connect_timeout 90; @@ -213,6 +215,9 @@ http { proxy_buffering off; proxy_cache off; proxy_request_buffering off; + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; } location ~ ^/auth/.*?(login|oidc/callback) { @@ -382,12 +387,14 @@ http { error_page 429 = @error429; location @error401 { - if ($request_uri ~* (^/connect/.*|^/oauth2/.*)) { - return 401; + if ($request_uri ~* (^/api/.*|^/connect/.*|^/oauth2/.*|^/.*\.map$)) { + return 401; } - if ($request_uri ~* ^/(?!(^/api/.*))) { + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; + + if ($request_uri ~* ^/(?!(login|auth|oauth2|$))) { add_header Set-Cookie "AUTH_REDIRECT=$request_uri;Path=/;Max-Age=14400"; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; } return 302 /auth/self-service/login/browser; } diff --git a/salt/nginx/soc_nginx.yaml b/salt/nginx/soc_nginx.yaml index 07abd32ce..c901c4ad9 100644 --- a/salt/nginx/soc_nginx.yaml +++ b/salt/nginx/soc_nginx.yaml @@ -1,12 +1,13 @@ nginx: - enabled: + enabled: description: Enables or disables the Nginx web server and reverse proxy. WARNING - Disabling this process will prevent access to SOC and other important web interfaces and APIs. Re-enabling the process is a manual effort. Do not change this setting without instruction from Security Onion support. + forcedType: bool advanced: True - helpLink: nginx.html + helpLink: nginx external_suricata: description: Enable this to allow external access to Suricata Rulesets managed by Detections. advanced: True - helplink: nginx.html + helpLink: nginx forcedType: bool ssl: replace_cert: @@ -15,27 +16,33 @@ nginx: advanced: True forcedType: bool title: Replace Default Cert - helpLink: nginx.html + helpLink: nginx ssl__key: description: If you enabled the replace_cert option, paste the contents of your .key file here. file: True title: SSL/TLS Key File advanced: True global: True - helpLink: nginx.html + helpLink: nginx ssl__crt: description: If you enabled the replace_cert option, paste the contents of your .crt file here. file: True title: SSL/TLS Cert File advanced: True global: True - helpLink: nginx.html + helpLink: nginx + alt_names: + description: Provide a list of alternate names to allow remote systems the ability to refer to the SOC API as another hostname. + global: True + forcedType: '[]string' + multiline: True + helpLink: nginx config: throttle_login_burst: description: Number of login requests that can burst without triggering request throttling. Higher values allow more repeated login attempts. Values greater than zero are required in order to provide a usable login flow. global: True - helpLink: nginx.html + helpLink: nginx throttle_login_rate: description: Number of login API requests per minute that can be processed without triggering a rate limit. Higher values allow more repeated login attempts. Requests are counted by unique client IP and averaged over time. Note that a single login flow will perform multiple requests to the login API, so this value will need to be adjusted accordingly. global: True - helpLink: nginx.html + helpLink: nginx diff --git a/salt/nginx/ssl.sls b/salt/nginx/ssl.sls new file mode 100644 index 000000000..b90f4af0a --- /dev/null +++ b/salt/nginx/ssl.sls @@ -0,0 +1,98 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'nginx/map.jinja' import NGINXMERGED %} +{% from 'ca/map.jinja' import CA %} + +{% if GLOBALS.role != 'so-fleet' %} +{# if the user has selected to replace the crt and key in the ui #} +{% if NGINXMERGED.ssl.replace_cert %} + +managerssl_key: + file.managed: + - name: /etc/pki/managerssl.key + - source: salt://nginx/ssl/ssl.key + - mode: 640 + - group: 939 + - watch_in: + - docker_container: so-nginx + +managerssl_crt: + file.managed: + - name: /etc/pki/managerssl.crt + - source: salt://nginx/ssl/ssl.crt + - mode: 644 + - watch_in: + - docker_container: so-nginx + +{% else %} + +managerssl_key: + x509.private_key_managed: + - name: /etc/pki/managerssl.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/managerssl.key') -%} + - prereq: + - x509: /etc/pki/managerssl.crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + - watch_in: + - docker_container: so-nginx + +# Create a cert for the reverse proxy +{% set san_list = [GLOBALS.hostname, GLOBALS.node_ip, GLOBALS.url_base] + NGINXMERGED.ssl.alt_names %} +{% set unique_san_list = san_list | unique %} +{% set managerssl_san_list = [] %} +{% for item in unique_san_list %} +{% if item | ipaddr %} +{% do managerssl_san_list.append("IP:" + item) %} +{% else %} +{% do managerssl_san_list.append("DNS:" + item) %} +{% endif %} +{% endfor %} +{% set managerssl_san = managerssl_san_list | join(', ') %} +managerssl_crt: + x509.certificate_managed: + - name: /etc/pki/managerssl.crt + - ca_server: {{ CA.server }} + - signing_policy: managerssl + - private_key: /etc/pki/managerssl.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: {{ managerssl_san }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + - watch_in: + - docker_container: so-nginx + +{% endif %} + +msslkeyperms: + file.managed: + - replace: False + - name: /etc/pki/managerssl.key + - mode: 640 + - group: 939 + +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/ntp/init.sls b/salt/ntp/init.sls index 1fc523e94..e5f322a4e 100644 --- a/salt/ntp/init.sls +++ b/salt/ntp/init.sls @@ -2,7 +2,6 @@ # 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 'vars/globals.map.jinja' import GLOBALS %} {% from 'ntp/config.map.jinja' import NTPCONFIG %} chrony_pkg: @@ -17,11 +16,7 @@ chronyconf: - defaults: NTPCONFIG: {{ NTPCONFIG }} -{% if GLOBALS.os_family == 'RedHat' %} chronyd: -{% else %} -chrony: -{% endif %} service.running: - enable: True - watch: diff --git a/salt/ntp/soc_ntp.yaml b/salt/ntp/soc_ntp.yaml index 1b75099a1..b50d2886f 100644 --- a/salt/ntp/soc_ntp.yaml +++ b/salt/ntp/soc_ntp.yaml @@ -3,4 +3,4 @@ ntp: servers: description: NTP Server List title: NTP Servers - helpLink: ntp.html + helpLink: ntp diff --git a/salt/patch/soc_patch.yaml b/salt/patch/soc_patch.yaml index 1618a0f75..b22c177f2 100644 --- a/salt/patch/soc_patch.yaml +++ b/salt/patch/soc_patch.yaml @@ -2,19 +2,20 @@ patch: os: enabled: description: Enable OS updates. WARNING - Disabling this setting will prevent important operating system updates from being applied on a scheduled basis. - helpLink: soup.html + forcedType: bool + helpLink: soup schedule_to_run: description: Currently running schedule for updates. - helpLink: soup.html + helpLink: soup schedules: auto: splay: &splayOptions description: Seconds to splay updates. - helpLink: soup.html + helpLink: soup schedule: hours: description: Run the OS updates every X hours. - helpLink: soup.html + helpLink: soup monday: splay: *splayOptions schedule: @@ -51,7 +52,7 @@ patch: Monday: &dailyOptions description: List of times to apply OS patches daily. multiline: True - helpLink: soup.html + helpLink: soup Tuesday: *dailyOptions Wednesday: *dailyOptions Thursday: *dailyOptions @@ -64,7 +65,7 @@ patch: Monday: &weekdayOptions description: List of times for weekdays. multiline: True - helpLink: soup.html + helpLink: soup Tuesday: *weekdayOptions Wednesday: *weekdayOptions Thursday: *weekdayOptions @@ -75,5 +76,5 @@ patch: Saturday: &weekendOptions description: List of times for weekend days. multiline: true - helpLink: soup.html + helpLink: soup Sunday: *weekendOptions diff --git a/salt/pcap/cleanup.sls b/salt/pcap/cleanup.sls new file mode 100644 index 000000000..e5ad2b6c5 --- /dev/null +++ b/salt/pcap/cleanup.sls @@ -0,0 +1,59 @@ +# 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 'vars/globals.map.jinja' import GLOBALS %} + +{% if GLOBALS.is_sensor %} + +delete_so-steno_so-status.conf: + file.line: + - name: /opt/so/conf/so-status/so-status.conf + - mode: delete + - match: so-steno + +remove_stenographer_user: + user.absent: + - name: stenographer + - force: True + +remove_stenographer_log_dir: + file.absent: + - name: /opt/so/log/stenographer + +remove_stenoloss_script: + file.absent: + - name: /opt/so/conf/telegraf/scripts/stenoloss.sh + +remove_steno_conf_dir: + file.absent: + - name: /opt/so/conf/steno + +remove_so_pcap_export: + file.absent: + - name: /usr/sbin/so-pcap-export + +remove_so_pcap_restart: + file.absent: + - name: /usr/sbin/so-pcap-restart + +remove_so_pcap_start: + file.absent: + - name: /usr/sbin/so-pcap-start + +remove_so_pcap_stop: + file.absent: + - name: /usr/sbin/so-pcap-stop + +so-steno: + docker_container.absent: + - force: True + +{% else %} + +{{sls}}.non_sensor_node: + test.show_notification: + - text: "Stenographer cleanup not applicable on non-sensor nodes." + +{% endif %} diff --git a/salt/pcap/config.map.jinja b/salt/pcap/config.map.jinja deleted file mode 100644 index e6d9f8bda..000000000 --- a/salt/pcap/config.map.jinja +++ /dev/null @@ -1,13 +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 'vars/globals.map.jinja' import GLOBALS %} -{% import_yaml 'pcap/defaults.yaml' as PCAPDEFAULTS %} -{% set PCAPMERGED = salt['pillar.get']('pcap', PCAPDEFAULTS.pcap, merge=True) %} - -{# disable stenographer if the pcap engine is set to SURICATA #} -{% if GLOBALS.pcap_engine == "SURICATA" %} -{% do PCAPMERGED.update({'enabled': False}) %} -{% endif %} diff --git a/salt/pcap/config.sls b/salt/pcap/config.sls deleted file mode 100644 index c37da9694..000000000 --- a/salt/pcap/config.sls +++ /dev/null @@ -1,93 +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.split('.')[0] in allowed_states %} - -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from "pcap/config.map.jinja" import PCAPMERGED %} -{% from 'bpf/pcap.map.jinja' import PCAPBPF, PCAP_BPF_STATUS, PCAP_BPF_CALC, STENO_BPF_COMPILED %} - -# PCAP Section -stenographergroup: - group.present: - - name: stenographer - - gid: 941 - -stenographer: - user.present: - - uid: 941 - - gid: 941 - - home: /opt/so/conf/steno - -stenoconfdir: - file.directory: - - name: /opt/so/conf/steno - - user: 941 - - group: 939 - - makedirs: True - -pcap_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://pcap/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -{% if PCAPBPF and not PCAP_BPF_STATUS %} -stenoPCAPbpfcompilationfailure: - test.configurable_test_state: - - changes: False - - result: False - - comment: "BPF Syntax Error - Discarding Specified BPF. Error: {{ PCAP_BPF_CALC['stderr'] }}" -{% endif %} - -stenoconf: - file.managed: - - name: /opt/so/conf/steno/config - - source: salt://pcap/files/config.jinja - - user: stenographer - - group: stenographer - - mode: 644 - - template: jinja - - defaults: - PCAPMERGED: {{ PCAPMERGED }} - STENO_BPF_COMPILED: "{{ STENO_BPF_COMPILED }}" - -stenoca: - file.directory: - - name: /opt/so/conf/steno/certs - - user: 941 - - group: 939 - -pcaptmpdir: - file.directory: - - name: /nsm/pcaptmp - - user: 941 - - group: 941 - - makedirs: True - -pcapindexdir: - file.directory: - - name: /nsm/pcapindex - - user: 941 - - group: 941 - - makedirs: True - -stenolog: - file.directory: - - name: /opt/so/log/stenographer - - user: 941 - - group: 941 - - makedirs: True - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} diff --git a/salt/pcap/defaults.yaml b/salt/pcap/defaults.yaml deleted file mode 100644 index 62c60e118..000000000 --- a/salt/pcap/defaults.yaml +++ /dev/null @@ -1,11 +0,0 @@ -pcap: - enabled: False - config: - maxdirectoryfiles: 30000 - diskfreepercentage: 10 - blocks: 2048 - preallocate_file_mb: 4096 - aiops: 128 - pin_to_cpu: False - cpus_to_pin_to: [] - disks: [] diff --git a/salt/pcap/disabled.sls b/salt/pcap/disabled.sls deleted file mode 100644 index 5643fc870..000000000 --- a/salt/pcap/disabled.sls +++ /dev/null @@ -1,27 +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.split('.')[0] in allowed_states %} - -include: - - pcap.sostatus - -so-steno: - docker_container.absent: - - force: True - -so-steno_so-status.disabled: - file.comment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-steno$ - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} diff --git a/salt/pcap/enabled.sls b/salt/pcap/enabled.sls deleted file mode 100644 index b7b030516..000000000 --- a/salt/pcap/enabled.sls +++ /dev/null @@ -1,62 +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.split('.')[0] in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} - - -include: - - pcap.config - - pcap.sostatus - -so-steno: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-steno:{{ GLOBALS.so_version }} - - start: True - - network_mode: host - - privileged: True - - binds: - - /opt/so/conf/steno/certs:/etc/stenographer/certs:rw - - /opt/so/conf/steno/config:/etc/stenographer/config:rw - - /nsm/pcap:/nsm/pcap:rw - - /nsm/pcapindex:/nsm/pcapindex:rw - - /nsm/pcaptmp:/tmp:rw - - /opt/so/log/stenographer:/var/log/stenographer:rw - {% if DOCKER.containers['so-steno'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-steno'].custom_bind_mounts %} - - {{ BIND }} - {% endfor %} - {% endif %} - {% if DOCKER.containers['so-steno'].extra_hosts %} - - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-steno'].extra_hosts %} - - {{ XTRAHOST }} - {% endfor %} - {% endif %} - {% if DOCKER.containers['so-steno'].extra_env %} - - environment: - {% for XTRAENV in DOCKER.containers['so-steno'].extra_env %} - - {{ XTRAENV }} - {% endfor %} - {% endif %} - - watch: - - file: stenoconf - - require: - - file: stenoconf - -delete_so-steno_so-status.disabled: - file.uncomment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-steno$ - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} diff --git a/salt/pcap/files/config.jinja b/salt/pcap/files/config.jinja deleted file mode 100644 index 90c197938..000000000 --- a/salt/pcap/files/config.jinja +++ /dev/null @@ -1,11 +0,0 @@ -{ - "Threads": [ - { "PacketsDirectory": "/nsm/pcap", "IndexDirectory": "/nsm/pcapindex", "MaxDirectoryFiles": {{ PCAPMERGED.config.maxdirectoryfiles }}, "DiskFreePercentage": {{ PCAPMERGED.config.diskfreepercentage }} } - ] - , "StenotypePath": "/usr/bin/stenotype" - , "Interface": "{{ pillar.sensor.interface }}" - , "Port": 1234 - , "Host": "127.0.0.1" - , "Flags": ["-v", "--blocks={{ PCAPMERGED.config.blocks }}", "--preallocate_file_mb={{ PCAPMERGED.config.preallocate_file_mb }}", "--aiops={{ PCAPMERGED.config.aiops }}", "--uid=stenographer", "--gid=stenographer"{{ STENO_BPF_COMPILED }}] - , "CertPath": "/etc/stenographer/certs" -} diff --git a/salt/pcap/init.sls b/salt/pcap/init.sls deleted file mode 100644 index 6812c2d91..000000000 --- a/salt/pcap/init.sls +++ /dev/null @@ -1,41 +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 'vars/globals.map.jinja' import GLOBALS %} -{% from 'pcap/config.map.jinja' import PCAPMERGED %} - -include: -{% if PCAPMERGED.enabled and GLOBALS.role != 'so-import'%} - - pcap.enabled -{% elif GLOBALS.role == 'so-import' %} - - pcap.config - - pcap.disabled -{% else %} - - pcap.disabled -{% endif %} - -# This directory needs to exist regardless of whether STENO is enabled or not, in order for -# Sensoroni to be able to look at old steno PCAP data - -# if stenographer has never run as the pcap engine no 941 user is created, so we use socore as a placeholder. -# /nsm/pcap is empty until stenographer is used as pcap engine -{% set pcap_id = 941 %} -{% set user_list = salt['user.list_users']() %} -{% if GLOBALS.pcap_engine == "SURICATA" and 'stenographer' not in user_list %} -{% set pcap_id = 939 %} -{% endif %} -pcapdir: - file.directory: - - name: /nsm/pcap - - user: {{ pcap_id }} - - group: {{ pcap_id }} - - makedirs: True - -pcapoutdir: - file.directory: - - name: /nsm/pcapout - - user: 939 - - group: 939 - - makedirs: True diff --git a/salt/pcap/soc_pcap.yaml b/salt/pcap/soc_pcap.yaml deleted file mode 100644 index 6b0c5a196..000000000 --- a/salt/pcap/soc_pcap.yaml +++ /dev/null @@ -1,35 +0,0 @@ -pcap: - enabled: - description: Enables or disables the Stenographer packet recording process. This process may already be disabled if Suricata is being used as the packet capture process. - helpLink: stenographer.html - config: - maxdirectoryfiles: - description: By default, Stenographer limits the number of files in the pcap directory to 30000 to avoid limitations with the ext3 filesystem. However, if you're using the ext4 or xfs filesystems, then it is safe to increase this value. So if you have a large amount of storage and find that you only have 3 weeks worth of PCAP on disk while still having plenty of free space, then you may want to increase this default setting. - helpLink: stenographer.html - diskfreepercentage: - description: Stenographer will purge old PCAP on a regular basis to keep the disk free percentage at this level. If you have a distributed deployment with dedicated Sensor nodes, then the default value of 10 should be reasonable since Stenographer should be the main consumer of disk space in the /nsm partition. However, if you have systems that run both Stenographer and Elasticsearch at the same time (like eval and standalone installations), then you’ll want to make sure that this value is no lower than 21 so that you avoid Elasticsearch hitting its watermark setting at 80% disk usage. If you have an older standalone installation, then you may need to manually change this value to 21. - helpLink: stenographer.html - blocks: - description: The number of 1MB packet blocks used by Stenographer and AF_PACKET to store packets in memory, per thread. You shouldn't need to change this. - advanced: True - helpLink: stenographer.html - preallocate_file_mb: - description: File size to pre-allocate for individual Stenographer PCAP files. You shouldn't need to change this. - advanced: True - helpLink: stenographer.html - aiops: - description: The max number of async writes to allow for Stenographer at once. - advanced: True - helpLink: stenographer.html - pin_to_cpu: - description: Enable CPU pinning for Stenographer PCAP. - advanced: True - helpLink: stenographer.html - cpus_to_pin_to: - description: CPU to pin Stenographer PCAP to. Currently only a single CPU is supported. - advanced: True - helpLink: stenographer.html - disks: - description: List of disks to use for Stenographer PCAP. This is currently not used. - advanced: True - helpLink: stenographer.html diff --git a/salt/pcap/sostatus.sls b/salt/pcap/sostatus.sls deleted file mode 100644 index 4eebbfb0e..000000000 --- a/salt/pcap/sostatus.sls +++ /dev/null @@ -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. - -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls.split('.')[0] in allowed_states %} - -append_so-steno_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-steno - - unless: grep -q so-steno /opt/so/conf/so-status/so-status.conf - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} diff --git a/salt/pcap/tools/sbin/so-pcap-start b/salt/pcap/tools/sbin/so-pcap-start deleted file mode 100755 index b65a35087..000000000 --- a/salt/pcap/tools/sbin/so-pcap-start +++ /dev/null @@ -1,12 +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. - - - -. /usr/sbin/so-common - -/usr/sbin/so-start steno $1 diff --git a/salt/pcap/tools/sbin/so-pcap-stop b/salt/pcap/tools/sbin/so-pcap-stop deleted file mode 100755 index 8f43841be..000000000 --- a/salt/pcap/tools/sbin/so-pcap-stop +++ /dev/null @@ -1,12 +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. - - - -. /usr/sbin/so-common - -/usr/sbin/so-stop steno $1 diff --git a/salt/podman/files/podman.service b/salt/podman/files/podman.service deleted file mode 100644 index eaa2ec437..000000000 --- a/salt/podman/files/podman.service +++ /dev/null @@ -1,17 +0,0 @@ -[Unit] -Description=Podman API Service -Requires=podman.socket -After=podman.socket -Documentation=man:podman-api(1) -StartLimitIntervalSec=0 - -[Service] -Type=oneshot -Environment=REGISTRIES_CONFIG_PATH=/etc/containers/registries.conf -ExecStart=/usr/bin/podman system service -TimeoutStopSec=30 -KillMode=process - -[Install] -WantedBy=multi-user.target -Also=podman.socket diff --git a/salt/podman/files/podman.socket b/salt/podman/files/podman.socket deleted file mode 100644 index 8b22e31e4..000000000 --- a/salt/podman/files/podman.socket +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Podman API Socket -Documentation=man:podman-api(1) - -[Socket] -ListenStream=%t/podman/podman.sock -SocketMode=0660 - -[Install] -WantedBy=sockets.target diff --git a/salt/podman/files/sobridge.conflist b/salt/podman/files/sobridge.conflist deleted file mode 100644 index 45a7e2df9..000000000 --- a/salt/podman/files/sobridge.conflist +++ /dev/null @@ -1,48 +0,0 @@ -{ - "args": { - "podman_options": { - "isolate": "true", - "mtu": "1500" - } - }, - "cniVersion": "0.4.0", - "name": "sobridge", - "plugins": [ - { - "type": "bridge", - "bridge": "sobridge", - "isGateway": true, - "ipMasq": false, - "mtu": 1500, - "hairpinMode": false, - "ipam": { - "type": "host-local", - "routes": [ - { - "dst": "0.0.0.0/0" - } - ], - "ranges": [ - [ - { - "subnet": "172.17.1.0/24", - "gateway": "172.17.1.1" - } - ] - ] - }, - "capabilities": { - "ips": true - } - }, - { - "type": "portmap", - "capabilities": { - "portMappings": false - } - }, - { - "type": "tuning" - } - ] -} diff --git a/salt/podman/init.sls b/salt/podman/init.sls deleted file mode 100644 index 119857840..000000000 --- a/salt/podman/init.sls +++ /dev/null @@ -1,56 +0,0 @@ -{% from 'docker/docker.map.jinja' import DOCKER %} - -Podman pkg: - pkg.installed: - - name: podman - -cnipkg: - pkg.installed: - - name: containernetworking-plugins - -{# -Podman service: - file.managed: - - name: /usr/lib/systemd/system/podman.service - - source: salt://podman/podman.service -#} - -sobridgeconf: - file.managed: - - name: /etc/cni/net.d/sobridge.conflist - - source: salt://podman/files/sobridge.conflist - -Podman_socket_service: - service.running: - - name: podman.socket - - enable: true - -Podman_service: - service.running: - - name: podman.service - - enable: true - -Docker socket: - file.symlink: - - name: /var/run/docker.sock - - target: /var/run/podman/podman.sock - -podman_docker_symlink: - file.symlink: - - name: /usr/bin/docker - - target: /usr/bin/podman - -{# -sos_docker_net: - docker_network.present: - - name: sobridge - - subnet: {{ DOCKER.range }} - - gateway: {{ DOCKER.bip }} - - options: - com.docker.network.bridge.name: 'sobridge' - com.docker.network.driver.mtu: '1500' - com.docker.network.bridge.enable_ip_masquerade: 'true' - com.docker.network.bridge.enable_icc: 'true' - com.docker.network.bridge.host_binding_ipv4: '0.0.0.0' - - unless: 'docker network ls | grep sobridge' -#} diff --git a/salt/redis/config.sls b/salt/redis/config.sls index 053d46707..11aaa1f0e 100644 --- a/salt/redis/config.sls +++ b/salt/redis/config.sls @@ -7,9 +7,6 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'redis/map.jinja' import REDISMERGED %} -include: - - ssl - # Redis Setup redisconfdir: file.directory: diff --git a/salt/redis/enabled.sls b/salt/redis/enabled.sls index fc206e3cb..4cea8d028 100644 --- a/salt/redis/enabled.sls +++ b/salt/redis/enabled.sls @@ -5,10 +5,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: + - ca + - redis.ssl - redis.config - redis.sostatus @@ -19,9 +21,9 @@ so-redis: - user: socore - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-redis'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-redis'].ip }} - port_bindings: - {% for BINDING in DOCKER.containers['so-redis'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-redis'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -31,40 +33,40 @@ so-redis: - /nsm/redis/data:/data:rw - /etc/pki/redis.crt:/certs/redis.crt:ro - /etc/pki/redis.key:/certs/redis.key:ro - {% if grains['role'] in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import'] %} - - /etc/pki/ca.crt:/certs/ca.crt:ro - {% else %} - /etc/pki/tls/certs/intca.crt:/certs/ca.crt:ro - {% endif %} - {% if DOCKER.containers['so-redis'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-redis'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-redis'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-redis'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-redis'].extra_hosts %} + {% if DOCKERMERGED.containers['so-redis'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-redis'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-redis'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-redis'].extra_env %} + {% if DOCKERMERGED.containers['so-redis'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-redis'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-redis'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-redis'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-redis'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - entrypoint: "redis-server /usr/local/etc/redis/redis.conf" - watch: - - file: /opt/so/conf/redis/etc - - require: - - file: redisconf + - file: trusttheca + - x509: redis_crt + - x509: redis_key + - file: /opt/so/conf/redis/etc + - require: + - file: trusttheca - x509: redis_crt - x509: redis_key - {% if grains['role'] in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import'] %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} delete_so-redis_so-status.disabled: file.uncomment: diff --git a/salt/redis/soc_redis.yaml b/salt/redis/soc_redis.yaml index 621cc0fbb..bce058bc3 100644 --- a/salt/redis/soc_redis.yaml +++ b/salt/redis/soc_redis.yaml @@ -1,18 +1,19 @@ redis: - enabled: + enabled: description: Enables the log event in-memory buffering process. This process might already be disabled on some installation types. Disabling this process on distributed-capable grids can result in loss of log events. - helpLink: redis.html + forcedType: bool + helpLink: redis config: bind: description: The IP address to bind to. global: True advanced: True - helpLink: redis.html + helpLink: redis protected-mode: description: Force authentication to access redis. global: True advanced: True - helpLink: redis.html + helpLink: redis requirepass: description: Password for accessing Redis. global: True @@ -21,262 +22,262 @@ redis: description: TLS cert file location. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-key-file: description: TLS key file location. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-ca-cert-file: description: TLS CA file location. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-port: description: Port to use TLS encryption on. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-auth-clients: description: Force TLS authentication. global: True advanced: True - helpLink: redis.html + helpLink: redis port: description: Non TLS port for Redis access. global: True advanced: True - helpLink: redis.html + helpLink: redis tcp-backlog: description: Set the TCP backlog value. This is normally increasd in high request environments. global: True advanced: True - helpLink: redis.html + helpLink: redis timeout: description: Time in seconds to close an idle connection. 0 to disable. global: True - helpLink: redis.html + helpLink: redis tcp-keepalive: description: Time in seconds to send a keepalive. global: True - helpLink: redis.html + helpLink: redis tls-replication: description: Enable TLS replication links. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-protocols: description: List of acceptable TLS protocols separated by spaces. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-prefer-server-ciphers: description: Prefer the server side ciphers. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-session-caching: description: Enable TLS session caching. global: True - helpLink: redis.html + helpLink: redis tls-session-cache-size: description: The number of TLS sessions to cache. global: True advanced: True - helpLink: redis.html + helpLink: redis tls-session-cache-timeout: description: Timeout in seconds to cache TLS sessions. global: True advanced: True - helpLink: redis.html + helpLink: redis loglevel: description: Log verbosity level. global: True - helpLink: redis.html + helpLink: redis logfile: description: Log file name. global: True advanced: True - helpLink: redis.html + helpLink: redis syslog-enabled: description: Enable syslog output. global: True advanced: True - helpLink: redis.html + helpLink: redis syslog-ident: description: Set the syslog identity. global: True advanced: True - helpLink: redis.html + helpLink: redis syslog-facility: description: Set the syslog facility. global: True advanced: True - helpLink: redis.html + helpLink: redis databases: description: Total amount of databases. global: True advanced: True - helpLink: redis.html + helpLink: redis always-show-logo: description: The amount of time that a write will wait before fsyncing. global: True advanced: True - helpLink: redis.html + helpLink: redis save: '900': description: Set the amount of keys that need to change to save after 15 minutes. global: True - helpLink: redis.html + helpLink: redis '300': description: Set the amount of keys that need to change to save after 5 minutes. global: True - helpLink: redis.html + helpLink: redis '60': description: Set the amount of keys that need to change to save after 1 minute global: True - helpLink: redis.html + helpLink: redis stop-writes-on-bgsave-error: description: Stop writes to redis is there is an error with the save. global: True advanced: True - helpLink: redis.html + helpLink: redis rdbcompression: description: Compress string objects with LZF. global: True advanced: True - helpLink: redis.html + helpLink: redis rdbchecksum: description: Enable checksum of rdb files. global: True advanced: True - helpLink: redis.html + helpLink: redis dbfilename: description: Filename of the rdb saves. global: True advanced: True - helpLink: redis.html + helpLink: redis acllog-max-len: description: Maximum length of the ACL log. global: True advanced: True - helpLink: redis.html + helpLink: redis maxmemory: description: Maximum memory for storing redis objects. global: True - helpLink: redis.html + helpLink: redis maxmemory-policy: description: The policy to use when maxmemory is reached. global: True - helpLink: redis.html + helpLink: redis maxmemory-samples: description: maxmemory sample size. global: True advanced: True - helpLink: redis.html + helpLink: redis lua-time-limit: description: Maximum execution time of LUA scripts. global: True advanced: True - helpLink: redis.html + helpLink: redis slowlog-log-slower-than: description: Time in microseconds to write to the slow log. global: True advanced: True - helpLink: redis.html + helpLink: redis slowlog-max-len: description: Maximum size of the slow log. global: True advanced: True - helpLink: redis.html + helpLink: redis hash-max-ziplist-entries: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis hash-max-ziplist-value: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis list-max-ziplist-size: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis list-compress-depth: description: Depth for list compression. global: True advanced: True - helpLink: redis.html + helpLink: redis set-max-intset-entries: description: Sets the limit on the size of the set in order to use the special memory saving encoding. global: True advanced: True - helpLink: redis.html + helpLink: redis zset-max-ziplist-entries: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis zset-max-ziplist-value: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis hll-sparse-max-bytes: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis stream-node-max-bytes: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis stream-node-max-entries: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis activerehashing: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis client-output-buffer-limit: normal: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis replica: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis pubsub: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis hz: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis dynamic-hz: description: Used for advanced performance tuning of Redis. global: True advanced: True - helpLink: redis.html + helpLink: redis rdb-save-incremental-fsync: description: fsync redis data. global: True advanced: True - helpLink: redis.html + helpLink: redis jemalloc-bg-thread: description: Jemalloc background thread for purging. global: True advanced: True - helpLink: redis.html + helpLink: redis diff --git a/salt/redis/ssl.sls b/salt/redis/ssl.sls new file mode 100644 index 000000000..cd68d900f --- /dev/null +++ b/salt/redis/ssl.sls @@ -0,0 +1,54 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/map.jinja' import CA %} + +redis_key: + x509.private_key_managed: + - name: /etc/pki/redis.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/redis.key') -%} + - prereq: + - x509: /etc/pki/redis.crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +redis_crt: + x509.certificate_managed: + - name: /etc/pki/redis.crt + - ca_server: {{ CA.server }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - signing_policy: registry + - private_key: /etc/pki/redis.key + - CN: {{ GLOBALS.hostname }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + +rediskeyperms: + file.managed: + - replace: False + - name: /etc/pki/redis.key + - mode: 640 + - group: 939 + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/registry/config.sls b/salt/registry/config.sls index 098633829..299d80437 100644 --- a/salt/registry/config.sls +++ b/salt/registry/config.sls @@ -6,9 +6,6 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -include: - - ssl - # Create the config directory for the docker registry dockerregistryconfdir: file.directory: diff --git a/salt/registry/enabled.sls b/salt/registry/enabled.sls index ed5b180cd..fc5021910 100644 --- a/salt/registry/enabled.sls +++ b/salt/registry/enabled.sls @@ -6,9 +6,10 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: + - registry.ssl - registry.config - registry.sostatus @@ -19,10 +20,10 @@ so-dockerregistry: - hostname: so-registry - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-dockerregistry'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-dockerregistry'].ip }} - restart_policy: always - port_bindings: - {% for BINDING in DOCKER.containers['so-dockerregistry'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-dockerregistry'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: @@ -31,28 +32,37 @@ so-dockerregistry: - /nsm/docker-registry/docker:/var/lib/registry/docker:rw - /etc/pki/registry.crt:/etc/pki/registry.crt:ro - /etc/pki/registry.key:/etc/pki/registry.key:ro - {% if DOCKER.containers['so-dockerregistry'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-dockerregistry'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-dockerregistry'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-dockerregistry'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-dockerregistry'].extra_hosts %} + {% if DOCKERMERGED.containers['so-dockerregistry'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-dockerregistry'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-dockerregistry'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - client_timeout: 180 - environment: - HOME=/root - {% if DOCKER.containers['so-dockerregistry'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-dockerregistry'].extra_env %} + {% if DOCKERMERGED.containers['so-dockerregistry'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-dockerregistry'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-dockerregistry'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-dockerregistry'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - retry: attempts: 5 interval: 30 + - watch: + - x509: registry_crt + - x509: registry_key - require: - file: dockerregistryconf - x509: registry_crt diff --git a/salt/registry/soc_registry.yaml b/salt/registry/soc_registry.yaml index 7d6cefe8c..7a936b343 100644 --- a/salt/registry/soc_registry.yaml +++ b/salt/registry/soc_registry.yaml @@ -1,4 +1,5 @@ registry: enabled: description: Enables or disables the Docker registry on the manager node. WARNING - If this process is disabled the grid will malfunction and a manual effort may be needed to re-enable the setting. + forcedType: bool advanced: True diff --git a/salt/registry/ssl.sls b/salt/registry/ssl.sls new file mode 100644 index 000000000..b739e9cc4 --- /dev/null +++ b/salt/registry/ssl.sls @@ -0,0 +1,77 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/map.jinja' import CA %} + +include: + - ca + +# Delete directory if it exists at the key path +registry_key_cleanup: + file.absent: + - name: /etc/pki/registry.key + - onlyif: + - test -d /etc/pki/registry.key + +registry_key: + x509.private_key_managed: + - name: /etc/pki/registry.key + - keysize: 4096 + - backup: True + - new: True + - require: + - file: registry_key_cleanup + {% if salt['file.file_exists']('/etc/pki/registry.key') -%} + - prereq: + - x509: /etc/pki/registry.crt + {%- endif %} + - retry: + attempts: 15 + interval: 10 + +# Delete directory if it exists at the crt path +registry_crt_cleanup: + file.absent: + - name: /etc/pki/registry.crt + - onlyif: + - test -d /etc/pki/registry.crt + +# Create a cert for the docker registry +registry_crt: + x509.certificate_managed: + - name: /etc/pki/registry.crt + - ca_server: {{ CA.server }} + - subjectAltName: DNS:{{ GLOBALS.manager }}, IP:{{ GLOBALS.manager_ip }} + - signing_policy: registry + - private_key: /etc/pki/registry.key + - CN: {{ GLOBALS.manager }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - require: + - file: registry_crt_cleanup + - timeout: 30 + - retry: + attempts: 15 + interval: 10 + + +regkeyperms: + file.managed: + - replace: False + - name: /etc/pki/registry.key + - mode: 640 + - group: 939 + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/repo/client/map.jinja b/salt/repo/client/map.jinja index 2c040c3c5..21f52a5e7 100644 --- a/salt/repo/client/map.jinja +++ b/salt/repo/client/map.jinja @@ -1,43 +1,29 @@ -{% from 'vars/globals.map.jinja' import GLOBALS %} - -{% if GLOBALS.os_family == 'RedHat' %} - {% set REPOPATH = '/etc/yum.repos.d/' %} -{% if GLOBALS.os == 'OEL' %} - {% set ABSENTFILES = [ - 'centos-addons.repo', - 'centos-devel.repo', - 'centos-extras.repo', - 'centos.repo', - 'docker-ce.repo', - 'epel.repo', - 'epel-testing.repo', - 'saltstack.repo', - 'salt-latest.repo', - 'wazuh.repo' - 'Rocky-Base.repo', - 'Rocky-CR.repo', - 'Rocky-Debuginfo.repo', - 'Rocky-fasttrack.repo', - 'Rocky-Media.repo', - 'Rocky-Sources.repo', - 'Rocky-Vault.repo', - 'Rocky-x86_64-kernel.repo', - 'rocky-addons.repo', - 'rocky-devel.repo', - 'rocky-extras.repo', - 'rocky.repo', - 'oracle-linux-ol9.repo', - 'uek-ol9.repo', - 'virt-ol9.repo' - ] - %} -{% else %} - {% set ABSENTFILES = [] %} -{% endif %} - -{% else %} - - {% set REPOPATH = '/etc/apt/sources.list.d/' %} - {% set ABSENTFILES = [] %} - -{% endif %} +{% set REPOPATH = '/etc/yum.repos.d/' %} +{% set ABSENTFILES = [ + 'centos-addons.repo', + 'centos-devel.repo', + 'centos-extras.repo', + 'centos.repo', + 'docker-ce.repo', + 'epel.repo', + 'epel-testing.repo', + 'saltstack.repo', + 'salt-latest.repo', + 'wazuh.repo' + 'Rocky-Base.repo', + 'Rocky-CR.repo', + 'Rocky-Debuginfo.repo', + 'Rocky-fasttrack.repo', + 'Rocky-Media.repo', + 'Rocky-Sources.repo', + 'Rocky-Vault.repo', + 'Rocky-x86_64-kernel.repo', + 'rocky-addons.repo', + 'rocky-devel.repo', + 'rocky-extras.repo', + 'rocky.repo', + 'oracle-linux-ol9.repo', + 'uek-ol9.repo', + 'virt-ol9.repo' + ] +%} diff --git a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja index 23fd15983..f8e5d5555 100644 --- a/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja +++ b/salt/salt/cloud/cloud.profiles.d/socloud.conf.jinja @@ -29,7 +29,11 @@ sool9_{{host}}: hypervisor_host: {{host ~ "_" ~ role}} preflight_cmds: - | - tee -a /etc/hosts <<< "{{ MANAGERIP }} {{ MANAGERHOSTNAME }}" + {%- set hostnames = [MANAGERHOSTNAME] %} + {%- if not (URL_BASE | ipaddr) and URL_BASE != MANAGERHOSTNAME %} + {%- do hostnames.append(URL_BASE) %} + {%- endif %} + tee -a /etc/hosts <<< "{{ MANAGERIP }} {{ hostnames | join(' ') }}" - | timeout 600 bash -c 'trap "echo \"Preflight Check: Failed to establish repo connectivity\"; exit 1" TERM; \ while ! dnf makecache --repoid=securityonion >/dev/null 2>&1; do echo "Preflight Check: Waiting for repo connectivity..."; \ diff --git a/salt/salt/cloud/config.sls b/salt/salt/cloud/config.sls index dce0e873a..cefd6ec78 100644 --- a/salt/salt/cloud/config.sls +++ b/salt/salt/cloud/config.sls @@ -14,6 +14,7 @@ {% if 'vrt' in salt['pillar.get']('features', []) %} {% set HYPERVISORS = salt['pillar.get']('hypervisor:nodes', {} ) %} {% from 'salt/map.jinja' import SALTVERSION %} +{% from 'vars/globals.map.jinja' import GLOBALS %} {% if HYPERVISORS %} cloud_providers: @@ -34,6 +35,7 @@ cloud_profiles: MANAGERHOSTNAME: {{ grains.host }} MANAGERIP: {{ pillar.host.mainip }} SALTVERSION: {{ SALTVERSION }} + URL_BASE: {{ GLOBALS.url_base }} - template: jinja - makedirs: True {% else %} diff --git a/salt/salt/engines/master/checkmine.py b/salt/salt/engines/master/checkmine.py index f33392575..68127bacb 100644 --- a/salt/salt/engines/master/checkmine.py +++ b/salt/salt/engines/master/checkmine.py @@ -46,33 +46,6 @@ def start(interval=60): mine_update(minion) continue - # if a manager check that the ca in in the mine and it is correct - if minion.split('_')[-1] in ['manager', 'managersearch', 'eval', 'standalone', 'import']: - x509 = __salt__['saltutil.runner']('mine.get', tgt=minion, fun='x509.get_pem_entries') - try: - ca_crt = x509[minion]['/etc/pki/ca.crt'] - log.debug('checkmine engine: found minion %s has ca_crt: %s' % (minion, ca_crt)) - # since the cert is defined, make sure it is valid - import salt.modules.x509_v2 as x509_v2 - if not x509_v2.verify_private_key('/etc/pki/ca.key', '/etc/pki/ca.crt'): - log.error('checkmine engine: found minion %s does\'t have a valid ca_crt in the mine' % (minion)) - log.error('checkmine engine: %s: ca_crt: %s' % (minion, ca_crt)) - mine_delete(minion, 'x509.get_pem_entries') - mine_update(minion) - continue - else: - log.debug('checkmine engine: found minion %s has a valid ca_crt in the mine' % (minion)) - except IndexError: - log.error('checkmine engine: found minion %s does\'t have a ca_crt in the mine' % (minion)) - mine_delete(minion, 'x509.get_pem_entries') - mine_update(minion) - continue - except KeyError: - log.error('checkmine engine: found minion %s is not in the mine' % (minion)) - mine_flush(minion) - mine_update(minion) - continue - # Update the mine if the ip in the mine doesn't match returned from manage.alived network_ip_addrs = __salt__['saltutil.runner']('mine.get', tgt=minion, fun='network.ip_addrs') try: diff --git a/salt/salt/engines/master/minimum_auth_version.py b/salt/salt/engines/master/minimum_auth_version.py new file mode 100644 index 000000000..1213cb5e1 --- /dev/null +++ b/salt/salt/engines/master/minimum_auth_version.py @@ -0,0 +1,73 @@ +# 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. + +# -*- coding: utf-8 -*- + +import logging +import os +import time +from datetime import datetime, timedelta +import salt.client + +log = logging.getLogger(__name__) + +TIMESTAMP_FILE = '/opt/so/state/mav_engine_start_time' + +def _get_start_time(): + """Read persisted start time from file, or create one if it doesn't exist.""" + if os.path.exists(TIMESTAMP_FILE): + with open(TIMESTAMP_FILE, 'r') as f: + timestamp = f.read().strip() + start_time = datetime.fromisoformat(timestamp) + log.info("Loaded existing start time from %s: %s", TIMESTAMP_FILE, start_time) + return start_time + + start_time = datetime.now() + with open(TIMESTAMP_FILE, 'w') as f: + f.write(start_time.isoformat()) + log.info("No existing start time found. Persisted new start time: %s", start_time) + return start_time + + +def _clear_start_time(): + """Remove the persisted timestamp file after successful completion.""" + if os.path.exists(TIMESTAMP_FILE): + os.remove(TIMESTAMP_FILE) + log.info("Removed timestamp file %s", TIMESTAMP_FILE) + + +def start(wait_days=7): + """ + This engine waits for the specified number of days, then changes minimum_auth_version. + + Args: + wait_days: Days to wait before taking action (default: 7) + """ + log.info( + "Starting minimum_auth_version engine - Wait time: %d days", + wait_days + ) + + start_time = _get_start_time() + wait_delta = timedelta(days=wait_days) + mav_removed = False + caller = salt.client.Caller() + + while True: + if not mav_removed: + elapsed = datetime.now() - start_time + + if elapsed >= wait_delta: + log.info("Changing minimum_auth_version") + _clear_start_time() + result = caller.cmd('state.apply', 'salt.master.remove_minimum_auth_version', queue=True) + # We shouldn't reach this line since the above line should remove the engine and restart salt-master + log.info("State apply result: %s", result) + mav_removed = True + else: + target_time = start_time + wait_delta + log.info("minimum_auth_version will be changed within an hour of %s", target_time.strftime('%m-%d-%Y %H:%M')) + + time.sleep(3600) # Check hourly diff --git a/salt/salt/engines/master/virtual_node_manager.py b/salt/salt/engines/master/virtual_node_manager.py index ccc063d64..dc3bb9720 100644 --- a/salt/salt/engines/master/virtual_node_manager.py +++ b/salt/salt/engines/master/virtual_node_manager.py @@ -805,11 +805,6 @@ def process_vm_creation(hypervisor_path: str, vm_config: dict) -> None: mark_invalid_hardware(hypervisor_path, vm_name, vm_config, {'nsm_size': 'Invalid nsm_size: must be positive integer'}) return - if size > 10000: # 10TB reasonable maximum - log.error("VM: %s - nsm_size %dGB exceeds reasonable maximum (10000GB)", vm_name, size) - mark_invalid_hardware(hypervisor_path, vm_name, vm_config, - {'nsm_size': f'Invalid nsm_size: {size}GB exceeds maximum (10000GB)'}) - return log.debug("VM: %s - nsm_size validated: %dGB", vm_name, size) except (ValueError, TypeError) as e: log.error("VM: %s - nsm_size must be a valid integer, got: %s", vm_name, vm_config.get('nsm_size')) diff --git a/salt/salt/init.sls b/salt/salt/init.sls index 724f79a95..cea67f46a 100644 --- a/salt/salt/init.sls +++ b/salt/salt/init.sls @@ -1,10 +1,3 @@ -{% if grains.oscodename == 'focal' %} -saltpymodules: - pkg.installed: - - pkgs: - - python3-docker -{% endif %} - # distribute to minions for salt upgrades salt_bootstrap: file.managed: diff --git a/salt/salt/map.jinja b/salt/salt/map.jinja index 62b7f1b18..ee886fb51 100644 --- a/salt/salt/map.jinja +++ b/salt/salt/map.jinja @@ -17,22 +17,12 @@ {% set SALTVERSION = saltminion.salt.minion.version | string %} {% set INSTALLEDSALTVERSION = grains.saltversion | string %} -{% if grains.os_family == 'Debian' %} - {% set SPLITCHAR = '+' %} - {% set SALTPACKAGES = ['salt-common', 'salt-master', 'salt-minion', 'salt-cloud'] %} - {% set SYSTEMD_UNIT_FILE = '/lib/systemd/system/salt-minion.service' %} -{% else %} - {% set SPLITCHAR = '-' %} - {% set SALTPACKAGES = ['salt', 'salt-master', 'salt-minion', 'salt-cloud'] %} - {% set SYSTEMD_UNIT_FILE = '/usr/lib/systemd/system/salt-minion.service' %} -{% endif %} +{% set SPLITCHAR = '-' %} +{% set SALTPACKAGES = ['salt', 'salt-master', 'salt-minion', 'salt-cloud'] %} +{% set SYSTEMD_UNIT_FILE = '/usr/lib/systemd/system/salt-minion.service' %} {% if INSTALLEDSALTVERSION != SALTVERSION %} - {% if grains.os_family|lower == 'redhat' %} - {% set UPGRADECOMMAND = 'yum clean all ; /usr/sbin/bootstrap-salt.sh -X -r -F stable ' ~ SALTVERSION %} - {% elif grains.os_family|lower == 'debian' %} - {% set UPGRADECOMMAND = '/usr/sbin/bootstrap-salt.sh -X -F stable ' ~ SALTVERSION %} - {% endif %} + {% set UPGRADECOMMAND = 'yum clean all ; /usr/sbin/bootstrap-salt.sh -X -r -F stable ' ~ SALTVERSION %} {% else %} {% set UPGRADECOMMAND = 'echo Already running Salt Minion version ' ~ SALTVERSION %} {% endif %} diff --git a/salt/salt/master.defaults.yaml b/salt/salt/master.defaults.yaml index 9dfe8587f..a54c33014 100644 --- a/salt/salt/master.defaults.yaml +++ b/salt/salt/master.defaults.yaml @@ -1,4 +1,4 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: master: - version: '3006.16' + version: '3006.19' diff --git a/salt/salt/master.sls b/salt/salt/master.sls index 6486e9126..895150cd7 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -23,15 +23,6 @@ sync_runners: - name: saltutil.sync_runners {% endif %} -# prior to 2.4.30 this engine ran on the manager with salt-minion -# this has changed to running with the salt-master in 2.4.30 -remove_engines_config: - file.absent: - - name: /etc/salt/minion.d/engines.conf - - source: salt://salt/files/engines.conf - - watch_in: - - service: salt_minion_service - checkmine_engine: file.managed: - name: /etc/salt/engines/checkmine.py diff --git a/salt/salt/master/add_minimum_auth_version.sls b/salt/salt/master/add_minimum_auth_version.sls new file mode 100644 index 000000000..768065a25 --- /dev/null +++ b/salt/salt/master/add_minimum_auth_version.sls @@ -0,0 +1,23 @@ +# 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. + +# This state is to be used during soup preupgrade_changes, and run when the salt-master has been stopped. Soup will later start the salt-master. +# This state is used to deal with the breaking change introduced in 3006.17 - https://docs.saltproject.io/en/3006/topics/releases/3006.17.html + + +set_minimum_auth_version_0: + file.managed: + - name: /etc/salt/master.d/minimum_auth_version.conf + - source: salt://salt/master/files/minimum_auth_version.conf + +add_minimum_auth_version_engine_config: + file.managed: + - name: /etc/salt/master.d/minimum_auth_version_engine.conf + - source: salt://salt/master/files/minimum_auth_version_engine.conf + +add_minimum_auth_version_engine: + file.managed: + - name: /etc/salt/engines/minimum_auth_version.py + - source: salt://salt/engines/master/minimum_auth_version.py diff --git a/salt/salt/master/files/minimum_auth_version.conf b/salt/salt/master/files/minimum_auth_version.conf new file mode 100644 index 000000000..29fd0c99d --- /dev/null +++ b/salt/salt/master/files/minimum_auth_version.conf @@ -0,0 +1 @@ +minimum_auth_version: 0 diff --git a/salt/salt/master/files/minimum_auth_version_engine.conf b/salt/salt/master/files/minimum_auth_version_engine.conf new file mode 100644 index 000000000..67e9ac654 --- /dev/null +++ b/salt/salt/master/files/minimum_auth_version_engine.conf @@ -0,0 +1,3 @@ +engines: + - minimum_auth_version: + wait_days: 7 diff --git a/salt/salt/master/remove_minimum_auth_version.sls b/salt/salt/master/remove_minimum_auth_version.sls new file mode 100644 index 000000000..2578e12fc --- /dev/null +++ b/salt/salt/master/remove_minimum_auth_version.sls @@ -0,0 +1,21 @@ +# 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. + +include: + - salt.master + +unset_minimum_auth_version_0: + file.absent: + - name: /etc/salt/master.d/minimum_auth_version.conf + +remove_minimum_auth_version_engine_config: + file.absent: + - name: /etc/salt/master.d/minimum_auth_version_engine.conf + +remove_minimum_auth_version_engine: + file.absent: + - name: /etc/salt/engines/minimum_auth_version.py + - watch_in: + - service: salt_master_service diff --git a/salt/salt/mine_functions.sls b/salt/salt/mine_functions.sls index ae3df1ce9..dd164503b 100644 --- a/salt/salt/mine_functions.sls +++ b/salt/salt/mine_functions.sls @@ -18,10 +18,6 @@ mine_functions: mine_functions: network.ip_addrs: - interface: {{ interface }} - {%- if role in ['so-eval','so-import','so-manager','so-managerhype','so-managersearch','so-standalone'] %} - x509.get_pem_entries: - - glob_path: '/etc/pki/ca.crt' - {% endif %} mine_update_mine_functions: module.run: diff --git a/salt/salt/minion.defaults.yaml b/salt/salt/minion.defaults.yaml index e897313d2..11f3dab41 100644 --- a/salt/salt/minion.defaults.yaml +++ b/salt/salt/minion.defaults.yaml @@ -1,5 +1,5 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: minion: - version: '3006.16' + version: '3006.19' check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default diff --git a/salt/salt/minion/init.sls b/salt/salt/minion/init.sls index 374e6954c..eb7018aed 100644 --- a/salt/salt/minion/init.sls +++ b/salt/salt/minion/init.sls @@ -17,23 +17,11 @@ include: - repo.client - salt.mine_functions - salt.minion.service_file -{% if GLOBALS.role in GLOBALS.manager_roles %} - - ca +{% if GLOBALS.is_manager %} + - ca.signing_policy {% endif %} {% if INSTALLEDSALTVERSION|string != SALTVERSION|string %} - -{# this is added in 2.4.120 to remove salt repo files pointing to saltproject.io to accomodate the move to broadcom and new bootstrap-salt script #} -{% if salt['pkg.version_cmp'](GLOBALS.so_version, '2.4.120') == -1 %} -{% set saltrepofile = '/etc/yum.repos.d/salt.repo' %} -{% if grains.os_family == 'Debian' %} -{% set saltrepofile = '/etc/apt/sources.list.d/salt.list' %} -{% endif %} -remove_saltproject_io_repo_minion: - file.absent: - - name: {{ saltrepofile }} -{% endif %} - unhold_salt_packages: pkg.unheld: - pkgs: @@ -111,7 +99,7 @@ salt_minion_service: {% if INSTALLEDSALTVERSION|string == SALTVERSION|string %} - file: set_log_levels {% endif %} -{% if GLOBALS.role in GLOBALS.manager_roles %} - - file: /etc/salt/minion.d/signing_policies.conf +{% if GLOBALS.is_manager %} + - file: signing_policy {% endif %} - order: last diff --git a/salt/salt/scripts/bootstrap-salt.sh b/salt/salt/scripts/bootstrap-salt.sh index 861f22de5..9324a0170 100644 --- a/salt/salt/scripts/bootstrap-salt.sh +++ b/salt/salt/scripts/bootstrap-salt.sh @@ -26,7 +26,7 @@ #====================================================================================================================== set -o nounset # Treat unset variables as an error -__ScriptVersion="2025.09.03" +__ScriptVersion="2026.01.22" __ScriptName="bootstrap-salt.sh" __ScriptFullName="$0" @@ -369,7 +369,7 @@ __usage() { also be specified. Salt installation will be ommitted, but some of the dependencies could be installed to write configuration with -j or -J. -d Disables checking if Salt services are enabled to start on system boot. - You can also do this by touching ${BS_TMP_DIR}/disable_salt_checks on the target + You can also do this by touching ${_TMP_DIR}/disable_salt_checks on the target host. Default: \${BS_FALSE} -D Show debug output -f Force shallow cloning for git installations. @@ -2819,14 +2819,25 @@ __install_salt_from_repo() { ${_pip_cmd} install --force-reinstall --break-system-packages "${_arch_dep}" fi - echodebug "Running '${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} ${_TMP_DIR}/git/deps/salt*.whl'" + _PIP_VERSION_STRING=$(${_pip_cmd} --version) + echodebug "Installed pip version: $_PIP_VERSION_STRING" + _PIP_MAJOR_VERSION=$(echo "$_PIP_VERSION_STRING" | sed -E 's/^pip ([0-9]+)\..*/\1/') - echodebug "Running ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} --global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} ${_TMP_DIR}/git/deps/salt*.whl" - - ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall \ - ${_PIP_INSTALL_ARGS} \ - --global-option="--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" \ - ${_TMP_DIR}/git/deps/salt*.whl || return 1 + # The following branching can be removed once we no longer support distros that still ship with + # versions of `pip` earlier than v22.1 such as Debian 11 + if [ "$_PIP_MAJOR_VERSION" -lt 23 ]; then + echodebug "Running ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} --global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} ${_TMP_DIR}/git/deps/salt*.whl" + ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall \ + ${_PIP_INSTALL_ARGS} \ + --global-option="--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" \ + ${_TMP_DIR}/git/deps/salt*.whl || return 1 + else + echodebug "Running ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall ${_PIP_INSTALL_ARGS} --config-settings=--global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS} ${_TMP_DIR}/git/deps/salt*.whl" + ${_pip_cmd} install ${_USE_BREAK_SYSTEM_PACKAGES} --no-deps --force-reinstall \ + ${_PIP_INSTALL_ARGS} \ + --config-settings="--global-option=--salt-config-dir=$_SALT_ETC_DIR --salt-cache-dir=${_SALT_CACHE_DIR} ${SETUP_PY_INSTALL_ARGS}" \ + ${_TMP_DIR}/git/deps/salt*.whl || return 1 + fi echoinfo "Checking if Salt can be imported using ${_py_exe}" CHECK_SALT_SCRIPT=$(cat << EOM @@ -6096,7 +6107,14 @@ install_arch_linux_git_deps() { } install_arch_linux_onedir_deps() { + echodebug "install_arch_linux_onedir_deps() entry" + + # Basic tooling for download/verify/extract + pacman -Sy --noconfirm --needed wget tar gzip gnupg ca-certificates || return 1 + + # Reuse stable deps for python-yaml etc. if you want config_salt() parity install_arch_linux_stable_deps || return 1 + return 0 } install_arch_linux_stable() { @@ -6111,7 +6129,73 @@ install_arch_linux_stable() { pacman -S --noconfirm --needed bash || return 1 pacman -Su --noconfirm || return 1 # We can now resume regular salt update - pacman -Syu --noconfirm salt || return 1 + # Except that this hasn't been in arch repos for years; + # so we have to build from AUR + # We use "buildgirl" because Eve demanded it. + build_user=${build_user:-buildgirl} + userdel "$build_user" || true + useradd -M -r -s /usr/bin/nologin "$build_user" + echo "$build_user ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/"$build_user" + rm -rf /tmp/yay-bin || true + + git clone https://aur.archlinux.org/salt.git /tmp/yay-bin + chown -R "$build_user":"$build_user" /tmp/yay-bin + sudo -u "$build_user" env -i \ + HOME=/tmp \ + PATH=/usr/bin:/bin:/usr/sbin:/sbin \ + MAKEFLAGS="-j$(nproc)" \ + LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 \ + makepkg -CcsiD /tmp/yay-bin \ + --noconfirm --needed \ + --noprogressbar || return 1 + + rm -f /etc/sudoers.d/"$build_user" + rm -rf /tmp/yay-bin + userdel "$build_user" + return 0 +} + +install_arch_linux_onedir() { + echodebug "install_arch_linux_onedir() entry" + + version="${ONEDIR_REV:-latest}" + arch="x86_64" + [ "$(uname -m)" = "aarch64" ] && arch="aarch64" + + # Resolve "latest" to actual version + if [ "$version" = "latest" ]; then + version=$(wget -qO- https://api.github.com/repos/saltstack/salt/releases/latest \ + | grep -Eo '"tag_name": *"v[0-9.]+"' \ + | sed 's/"tag_name": *"v//;s/"//') || return 1 + fi + + tarball="salt-${version}-onedir-linux-${arch}.tar.xz" + url="https://github.com/saltstack/salt/releases/download/v${version}/${tarball}" + extractdir="/tmp/salt-${version}-onedir-linux-${arch}" + + echoinfo "Downloading Salt onedir: $url" + wget -q "$url" -O "/tmp/${tarball}" || return 1 + + # Validate tarball + if ! tar -tf "/tmp/${tarball}" >/dev/null 2>&1; then + echoerror "Invalid or corrupt onedir tarball" + return 1 + fi + + # Prepare extraction + rm -rf "$extractdir" || true + rm -rf /opt/saltstack/salt || true + mkdir -p "$extractdir" + + # Extract and flatten (remove leading 'salt/' directory) + # /tmp/salt-${version}-onedir-linux-${arch} + tar --strip-components=1 -xf "/tmp/${tarball}" -C "$extractdir" + + # Place into /opt + mkdir -p /opt/saltstack/salt + mv "$extractdir"/* /opt/saltstack/salt/ || return 1 + chmod -R 755 /opt/saltstack/salt + return 0 } @@ -6249,17 +6333,48 @@ install_arch_check_services() { return 0 } -install_arch_linux_onedir() { - install_arch_linux_stable || return 1 - return 0 -} install_arch_linux_onedir_post() { - install_arch_linux_post || return 1 + echodebug "install_arch_linux_onedir_post() entry" - return 0 + # Disable any distro/AUR salt units + systemctl disable --now salt-minion.service 2>/dev/null || true + systemctl disable --now salt-master.service 2>/dev/null || true + + # Drop a clean unit, same pattern as Debian/Ubuntu onedir + cat >/etc/systemd/system/salt-minion.service <<'EOF' +[Unit] +Description=Salt Minion (onedir) +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +ExecStart=/opt/saltstack/salt/salt-minion -c /etc/salt +Restart=always +LimitNOFILE=100000 + +[Install] +WantedBy=multi-user.target +EOF + + systemctl daemon-reload + + # Add onedir paths system-wide + cat >/etc/profile.d/saltstack.sh <<'EOF' +export PATH=/opt/saltstack/salt:/opt/saltstack/salt/bin:$PATH +EOF + + chmod 644 /etc/profile.d/saltstack.sh + + if [ "$_START_DAEMONS" -eq $BS_TRUE ]; then + systemctl enable --now salt-minion.service + fi + + return 0 } + # # Ended Arch Install Functions # diff --git a/salt/sensor/soc_sensor.yaml b/salt/sensor/soc_sensor.yaml index f97c8d849..17a650a07 100644 --- a/salt/sensor/soc_sensor.yaml +++ b/salt/sensor/soc_sensor.yaml @@ -1,15 +1,15 @@ sensor: interface: description: Main sensor monitoring interface. - helpLink: network.html + helpLink: network-visibility readonly: True mtu: description: Maximum Transmission Unit (MTU) of the sensor monitoring interface. - helpLink: network.html + helpLink: network-visibility readonly: True channels: description: Set the size of the nic channels. This is rarely changed from 1 - helpLink: network.html + helpLink: network-visibility forcedType: int node: True advanced: True diff --git a/salt/sensoroni/enabled.sls b/salt/sensoroni/enabled.sls index 4b0b6b317..7790574f6 100644 --- a/salt/sensoroni/enabled.sls +++ b/salt/sensoroni/enabled.sls @@ -4,7 +4,7 @@ # Elastic License 2.0. {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: @@ -16,8 +16,6 @@ so-sensoroni: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soc:{{ GLOBALS.so_version }} - network_mode: host - binds: - - /opt/so/conf/steno/certs:/etc/stenographer/certs:rw - - /nsm/pcap:/nsm/pcap:rw - /nsm/import:/nsm/import:rw - /nsm/pcapout:/nsm/pcapout:rw - /opt/so/conf/sensoroni/sensoroni.json:/opt/sensoroni/sensoroni.json:ro @@ -25,23 +23,29 @@ so-sensoroni: - /opt/so/conf/sensoroni/templates:/opt/sensoroni/templates:ro - /opt/so/log/sensoroni:/opt/sensoroni/logs:rw - /nsm/suripcap/:/nsm/suripcap:rw - {% if DOCKER.containers['so-sensoroni'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-sensoroni'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-sensoroni'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-sensoroni'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-sensoroni'].extra_hosts %} + {% if DOCKERMERGED.containers['so-sensoroni'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-sensoroni'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-sensoroni'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-sensoroni'].extra_env %} + {% if DOCKERMERGED.containers['so-sensoroni'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-sensoroni'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-sensoroni'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-sensoroni'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-sensoroni'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: /opt/so/conf/sensoroni/sensoroni.json - require: diff --git a/salt/sensoroni/files/analyzers/elasticsearch/README.md b/salt/sensoroni/files/analyzers/elasticsearch/README.md index 6ee4dadd0..d8aacbee3 100644 --- a/salt/sensoroni/files/analyzers/elasticsearch/README.md +++ b/salt/sensoroni/files/analyzers/elasticsearch/README.md @@ -14,7 +14,7 @@ An API key or User Credentials is necessary for utilizing Elasticsearch. In SOC, navigate to `Administration`, toggle `Show all configurable settings, including advanced settings.`, and navigate to `sensoroni` -> `analyzers` -> `elasticsearch`. -![image](https://github.com/Security-Onion-Solutions/securityonion/blob/2.4/dev/assets/images/screenshots/analyzers/elasticsearch.png?raw=true) +![image](https://github.com/Security-Onion-Solutions/securityonion/blob/3/dev/assets/images/screenshots/analyzers/elasticsearch.png?raw=true) The following configuration options are available for: diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/elasticsearch/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/emailrep/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/greynoise/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/localfile/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarebazaar/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_whois-0.9.5-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_whois-0.9.5-py3-none-any.whl deleted file mode 100644 index d92bc8729..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_whois-0.9.5-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_whois-0.9.6-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_whois-0.9.6-py3-none-any.whl new file mode 100644 index 000000000..c588b3c19 Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/python_whois-0.9.6-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/malwarehashregistry/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/otx/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/otx/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/otx/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/pulsedive/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/spamhaus/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.7.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.7.0-py3-none-any.whl deleted file mode 100644 index ebbf41c69..000000000 Binary files a/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.7.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.8.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.8.0-py3-none-any.whl new file mode 100644 index 000000000..d618ba05d Binary files /dev/null and b/salt/sensoroni/files/analyzers/spamhaus/source-packages/dnspython-2.8.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/spamhaus/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/spamhaus/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/spamhaus/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/README.md b/salt/sensoroni/files/analyzers/sublime/README.md index 0516af9a1..c76008531 100644 --- a/salt/sensoroni/files/analyzers/sublime/README.md +++ b/salt/sensoroni/files/analyzers/sublime/README.md @@ -6,7 +6,7 @@ Submit a base64-encoded EML file to Sublime Platform for analysis. ## Configuration Requirements In SOC, navigate to `Administration`, toggle `Show all configurable settings, including advanced settings.`, and navigate to `sensoroni` -> `analyzers` -> `sublime_platform`. -![image](https://github.com/Security-Onion-Solutions/securityonion/blob/2.4/dev/assets/images/screenshots/analyzers/sublime.png?raw=true) +![image](https://github.com/Security-Onion-Solutions/securityonion/blob/3/dev/assets/images/screenshots/analyzers/sublime.png?raw=true) The following configuration options are available for: diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/sublime/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/threatfox/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/threatfox/threatfox.json b/salt/sensoroni/files/analyzers/threatfox/threatfox.json index 2ae3ca909..e9640e7d5 100644 --- a/salt/sensoroni/files/analyzers/threatfox/threatfox.json +++ b/salt/sensoroni/files/analyzers/threatfox/threatfox.json @@ -1,6 +1,6 @@ { "name": "Threatfox", - "version": "0.2", + "version": "0.3", "author": "Security Onion Solutions", "description": "This analyzer queries Threatfox to see if a domain, hash, or IP is considered malicious.", "supportedTypes" : ["domain","hash","ip"], diff --git a/salt/sensoroni/files/analyzers/threatfox/threatfox.py b/salt/sensoroni/files/analyzers/threatfox/threatfox.py index a20f072ed..02311bfab 100644 --- a/salt/sensoroni/files/analyzers/threatfox/threatfox.py +++ b/salt/sensoroni/files/analyzers/threatfox/threatfox.py @@ -51,7 +51,7 @@ def prepareResults(raw): status = 'info' else: status = 'ok' - elif raw != {} and raw['query_status'] in ['no_result', 'illegal_search_term', 'illegl_hash']: + elif raw != {} and raw['query_status'] in ['no_result', 'illegal_search_term', 'illegal_hash']: status = 'info' summary = 'no result' else: diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlhaus/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/urlscan/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl deleted file mode 100644 index e7e59e816..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..619184508 Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/virustotal/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/anyio-4.10.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/anyio-4.10.0-py3-none-any.whl deleted file mode 100644 index ba752083e..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/anyio-4.10.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/anyio-4.12.1-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/anyio-4.12.1-py3-none-any.whl new file mode 100644 index 000000000..328780949 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/anyio-4.12.1-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2025.8.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2025.8.3-py3-none-any.whl deleted file mode 100644 index b4158ec67..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2025.8.3-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.2.25-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.2.25-py3-none-any.whl new file mode 100644 index 000000000..9d7fbf09d Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/certifi-2026.2.25-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl deleted file mode 100644 index a8f2bd0c4..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl new file mode 100644 index 000000000..06be5ddd0 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/charset_normalizer-3.4.6-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/exceptiongroup-1.3.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/exceptiongroup-1.3.0-py3-none-any.whl deleted file mode 100644 index 50bf3af10..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/exceptiongroup-1.3.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/idna-3.10-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/idna-3.10-py3-none-any.whl deleted file mode 100644 index 52759bdd2..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/idna-3.10-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/idna-3.11-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/idna-3.11-py3-none-any.whl new file mode 100644 index 000000000..28f2c109e Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/idna-3.11-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/sniffio-1.3.1-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/sniffio-1.3.1-py3-none-any.whl deleted file mode 100644 index 04f44e47d..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/sniffio-1.3.1-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/typing_extensions-4.14.1-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/typing_extensions-4.14.1-py3-none-any.whl deleted file mode 100644 index d2aef8cf2..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/typing_extensions-4.14.1-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/typing_extensions-4.15.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/typing_extensions-4.15.0-py3-none-any.whl new file mode 100644 index 000000000..5fec9ca64 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/typing_extensions-4.15.0-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/urllib3-2.5.0-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/urllib3-2.5.0-py3-none-any.whl deleted file mode 100644 index 81b580f1c..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/urllib3-2.5.0-py3-none-any.whl and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/urllib3-2.6.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/urllib3-2.6.3-py3-none-any.whl new file mode 100644 index 000000000..69e9ea57b Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/urllib3-2.6.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-3.1.1.tar.gz b/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-3.1.1.tar.gz deleted file mode 100644 index e46573efd..000000000 Binary files a/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-3.1.1.tar.gz and /dev/null differ diff --git a/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.0.3-py3-none-any.whl b/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.0.3-py3-none-any.whl new file mode 100644 index 000000000..8107b57f6 Binary files /dev/null and b/salt/sensoroni/files/analyzers/whoislookup/source-packages/whoisit-4.0.3-py3-none-any.whl differ diff --git a/salt/sensoroni/files/sensoroni.json b/salt/sensoroni/files/sensoroni.json index a0f512fa2..2e7ab0860 100644 --- a/salt/sensoroni/files/sensoroni.json +++ b/salt/sensoroni/files/sensoroni.json @@ -32,11 +32,6 @@ "apiKey": "{{ GLOBALS.sensoroni_key }}" {% if GLOBALS.is_sensor %} }, - "stenoquery": { - "executablePath": "/opt/sensoroni/scripts/stenoquery.sh", - "pcapInputPath": "/nsm/pcap", - "pcapOutputPath": "/nsm/pcapout" - }, "suriquery": { "pcapInputPath": "/nsm/suripcap", "pcapOutputPath": "/nsm/pcapout", diff --git a/salt/sensoroni/files/templates/reports/standard/assistant_session_report.md b/salt/sensoroni/files/templates/reports/standard/assistant_session_report.md new file mode 100644 index 000000000..7879a7db0 --- /dev/null +++ b/salt/sensoroni/files/templates/reports/standard/assistant_session_report.md @@ -0,0 +1,91 @@ +Onion AI Session Report +========================== + +## Session Details + +**Session ID:** {{.Session.SessionId}} + +**Title:** {{.Session.Title}} + +**Created:** {{formatDateTime "Mon Jan 02 15:04:05 -0700 2006" .Session.CreateTime}} + +**Updated:** {{formatDateTime "Mon Jan 02 15:04:05 -0700 2006" .Session.UpdateTime}} + +{{ if .Session.DeleteTime }} +**Deleted:** {{ formatDateTime "Mon Jan 02 15:04:05 -0700 2006" .Session.DeleteTime}} +{{ end }} + +**User ID:** {{getUserDetail "email" .Session.UserId}} + +## Session Usage + +**Total Input Tokens** {{.Session.Usage.TotalInputTokens}} + +**Total Output Tokens** {{.Session.Usage.TotalOutputTokens}} + +**Total Credits:** {{.Session.Usage.TotalCredits}} + +**Total Messages:** {{.Session.Usage.TotalMessages}} + +## Messages + +{{ range $index, $msg := sortAssistantMessages "CreateTime" "asc" .History }} +#### Message {{ add $index 1 }} + +**Created:** {{formatDateTime "Mon Jan 02 15:04:05 -0700 2006" $msg.CreateTime}} + +**User ID:** {{getUserDetail "email" $msg.UserId}} + +**Role:** {{$msg.Message.Role}} + +{{ range $i, $block := $msg.Message.ContentBlocks }} + +--- + +{{ if eq $block.Type "text" }} +**Text:** {{ stripEmoji $block.Text }} +{{ else if eq $block.Type "tool_use" }} +**Tool:** {{ $block.Name }} +{{ if $block.Input }} +**Parameters:** +{{ range $key, $value := parseJSON $block.Input }} +{{ if eq $key "limit" }}- {{ $key }}: {{ $value }} +{{ else }}- {{ $key }}: "{{ $value }}" +{{ end }}{{ end }}{{ end }} +{{ else if $block.ToolResult }} +**Tool Result:** +{{ if $block.ToolResult.Content }} +{{ range $j, $contentBlock := $block.ToolResult.Content }} +{{ if gt $j 0 }} + +--- + +{{ end }} +{{ if $contentBlock.Text }} +{{ if $block.ToolResult.IsError }} +**Error:** {{ $contentBlock.Text }} +{{ else }} +{{ $contentBlock.Text }} +{{ end }} +{{ else if $contentBlock.Json }} +```json +{{ toJSON $contentBlock.Json }} +``` +{{ end }}{{ end }} +{{ end }}{{ end }}{{ end }} + +{{ if eq $msg.Message.Role "assistant" }}{{ if $msg.Message.Usage }} + +--- + +**Message Usage:** + +- Input Tokens: {{$msg.Message.Usage.InputTokens}} +- Output Tokens: {{$msg.Message.Usage.OutputTokens}} +- Credits: {{$msg.Message.Usage.Credits}} + +{{end}}{{end}} + +--- + +{{end}} \ No newline at end of file diff --git a/salt/sensoroni/files/templates/reports/standard/case_report.md b/salt/sensoroni/files/templates/reports/standard/case_report.md index 49f18e7c6..76a166f3f 100644 --- a/salt/sensoroni/files/templates/reports/standard/case_report.md +++ b/salt/sensoroni/files/templates/reports/standard/case_report.md @@ -130,4 +130,42 @@ Security Onion Case Report | ---- | ---- | ------ | --------- | {{ range sortHistory "CreateTime" "asc" .History -}} | {{formatDateTime "Mon Jan 02 15:04:05 -0700 2006" .CreateTime}} | {{getUserDetail "email" .UserId}} | {{.Kind}} | {{.Operation}} | +{{end}} + +## Attached Onion AI Sessions + +{{ range $idx, $session := sortAssistantSessionDetails "CreateTime" "desc" .AssistantSessions }} + +#### Session {{ add $idx 1 }} + +**Session ID:** {{$session.Session.SessionId}} + +**Title:** {{$session.Session.Title}} + +**User ID:** {{getUserDetail "email" $session.Session.UserId}} + +**Created:** {{formatDateTime "Mon Jan 02 15:04:05 -0700 2006" $session.Session.CreateTime}} + +**Updated:** {{formatDateTime "Mon Jan 02 15:04:05 -0700 2006" $session.Session.UpdateTime}} + +{{ if $session.Session.DeleteTime }} +**Deleted:** {{ formatDateTime "Mon Jan 02 15:04:05 -0700 2006" $session.Session.DeleteTime}} +{{ end }} + +#### Messages + +{{ range $index, $msg := sortAssistantMessages "CreateTime" "asc" $session.History }} +{{ range $i, $block := $msg.Message.ContentBlocks }} + +{{ if eq $block.Type "text" }} + +**Role:** {{$msg.Message.Role}} + +{{ stripEmoji $block.Text }} + +--- + +{{ end }}{{ end }} + +{{end}} {{end}} \ No newline at end of file diff --git a/salt/sensoroni/soc_sensoroni.yaml b/salt/sensoroni/soc_sensoroni.yaml index cf69ec52a..73920e9b7 100644 --- a/salt/sensoroni/soc_sensoroni.yaml +++ b/salt/sensoroni/soc_sensoroni.yaml @@ -1,80 +1,82 @@ sensoroni: enabled: description: Enable or disable the per-node SOC agent process. This process is used for performing node-related jobs and reporting node metrics back to SOC. Disabling this process is unsupported and will result in an improperly functioning grid. + forcedType: bool advanced: True - helpLink: grid.html + helpLink: grid config: analyze: enabled: description: Enable or disable the analyzer. + forcedType: bool advanced: True - helpLink: cases.html + helpLink: cases timeout_ms: description: Timeout period for the analyzer. advanced: True - helpLink: cases.html + helpLink: cases parallel_limit: description: Parallel limit for the analyzer. advanced: True - helpLink: cases.html + helpLink: cases export: timeout_ms: description: Timeout period for the exporter to finish export-related tasks. advanced: True - helpLink: reports.html + helpLink: reports cache_refresh_interval_ms: description: Refresh interval for cache updates. Longer intervals result in less compute usage but risks stale data included in reports. advanced: True - helpLink: reports.html + helpLink: reports export_metric_limit: description: Maximum number of metric values to include in each metric aggregation group. advanced: True - helpLink: reports.html + helpLink: reports export_event_limit: description: Maximum number of events to include per event list. advanced: True - helpLink: reports.html + helpLink: reports csv_separator: description: Separator character to use for CSV exports. advanced: False - helpLink: reports.html + helpLink: reports node_checkin_interval_ms: description: Interval in ms to checkin to the soc_host. advanced: True - helpLink: grid.html + helpLink: grid node_description: description: Description of the specific node. - helpLink: grid.html + helpLink: grid node: True forcedType: string sensoronikey: description: Shared key for sensoroni authentication. - helpLink: grid.html + helpLink: grid global: True sensitive: True advanced: True soc_host: description: Host for sensoroni agents to connect to. - helpLink: grid.html + helpLink: grid global: True advanced: True suripcap: pcapMaxCount: description: The maximum number of PCAP packets to extract from eligible PCAP files, for PCAP jobs. If there are issues fetching excessively large packet streams consider lowering this value to reduce the number of collected packets returned to the user interface. - helpLink: sensoroni.html + helpLink: pcap advanced: True analyzers: echotrail: api_key: description: API key for the Echotrail analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: True advanced: False forcedType: string base_url: description: Base URL for the Echotrail analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: False @@ -82,70 +84,70 @@ sensoroni: elasticsearch: api_key: description: API key for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: True advanced: True forcedType: string base_url: description: Connection URL for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: False forcedType: string auth_user: description: Username for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: False forcedType: string auth_pwd: description: User password for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: True advanced: False forcedType: string num_results: description: Number of documents to return for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: True forcedType: string index: description: Search index for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: False forcedType: string time_delta_minutes: description: Time (in minutes) to search back for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: True forcedType: int timestamp_field_name: description: Specified name for a documents' timestamp field for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: True forcedType: string map: description: Map between observable types and search field for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: False forcedType: string cert_path: description: Path to a TLS certificate for the Elasticsearch analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: False advanced: False @@ -153,14 +155,14 @@ sensoroni: emailrep: api_key: description: API key for the EmailRep analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string base_url: description: Base URL for the EmailRep analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -168,21 +170,21 @@ sensoroni: greynoise: api_key: description: API key for the GreyNoise analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string api_version: description: API version for the GreyNoise analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: string base_url: description: Base URL for the GreyNoise analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -190,7 +192,7 @@ sensoroni: localfile: file_path: description: File path for the LocalFile analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -198,7 +200,7 @@ sensoroni: malwarebazaar: api_key: description: API key for the malwarebazaar analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: True advanced: False @@ -206,14 +208,14 @@ sensoroni: otx: api_key: description: API key for the OTX analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string base_url: description: Base URL for the OTX analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -221,14 +223,14 @@ sensoroni: pulsedive: api_key: description: API key for the Pulsedive analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string base_url: description: Base URL for the Pulsedive analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -236,14 +238,14 @@ sensoroni: spamhaus: lookup_host: description: Host to use for lookups. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: string nameservers: description: Nameservers used for queries. - helpLink: cases.html + helpLink: cases global: False sensitive: False multiline: True @@ -252,35 +254,35 @@ sensoroni: sublime_platform: api_key: description: API key for the Sublime Platform analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string base_url: description: Base URL for the Sublime Platform analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: string live_flow: description: Determines if live flow analysis is used. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: bool mailbox_email_address: description: Source mailbox address used for live flow analysis. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: string message_source_id: description: ID of the message source used for live flow analysis. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -288,7 +290,7 @@ sensoroni: threatfox: api_key: description: API key for the threatfox analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: True advanced: False @@ -296,35 +298,35 @@ sensoroni: urlscan: api_key: description: API key for the Urlscan analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string base_url: description: Base URL for the Urlscan analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: string enabled: description: Analyzer enabled - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: bool timeout: description: Timeout for the Urlscan analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True forcedType: int visibility: description: Type of visibility. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -332,7 +334,7 @@ sensoroni: urlhaus: api_key: description: API key for the urlhaus analyzer. - helpLink: sensoroni.html + helpLink: cases#configuring-analyzers global: False sensitive: True advanced: False @@ -340,14 +342,14 @@ sensoroni: virustotal: api_key: description: API key for the VirusTotal analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: True advanced: True forcedType: string base_url: description: Base URL for the VirusTotal analyzer. - helpLink: cases.html + helpLink: cases global: False sensitive: False advanced: True @@ -357,19 +359,26 @@ sensoroni: reports: standard: case_report__md: - title: Case report Template + title: Case Report Template description: The template used when generating a case report. Supports markdown format. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports productivity_report__md: title: Productivity Report Template description: The template used when generating a comprehensive productivity report. Supports markdown format. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports + assistant_session_report__md: + title: Assistant Session Report Template + description: The template used when generating an assistant session report. Supports markdown format. + file: True + global: True + syntax: md + helpLink: reports custom: generic_report1__md: title: Custom Report 1 @@ -377,63 +386,63 @@ sensoroni: file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report2__md: title: Custom Report 2 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report3__md: title: Custom Report 3 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report4__md: title: Custom Report 4 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report5__md: title: Custom Report 5 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report6__md: title: Custom Report 6 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report7__md: title: Custom Report 7 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report8__md: title: Custom Report 8 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports generic_report9__md: title: Custom Report 9 description: A custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. file: True global: True syntax: md - helpLink: reports.html + helpLink: reports addl_generic_report__md: title: Additional Custom Report description: A duplicatable custom, user-defined report. Supports markdown format. The report title inside the file, typically near the top, will be shown in the SOC reporting UI. This is an unsupported feature due to the inability to edit duplicated reports via the SOC app. @@ -442,4 +451,4 @@ sensoroni: global: True syntax: md duplicates: True - helpLink: reports.html \ No newline at end of file + helpLink: reports diff --git a/salt/soc/defaults.map.jinja b/salt/soc/defaults.map.jinja index a2e72bcca..2821bb8e5 100644 --- a/salt/soc/defaults.map.jinja +++ b/salt/soc/defaults.map.jinja @@ -5,7 +5,7 @@ {% import_yaml 'soc/defaults.yaml' as SOCDEFAULTS %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER -%} +{% from 'docker/docker.map.jinja' import DOCKERMERGED -%} {% set INFLUXDB_TOKEN = salt['pillar.get']('influxdb:token') %} {% import_text 'influxdb/metrics_link.txt' as METRICS_LINK %} @@ -32,7 +32,7 @@ {% endif %} {% endfor %} -{% do SOCDEFAULTS.soc.config.server.modules.statickeyauth.update({'anonymousCidr': DOCKER.range, 'apiKey': pillar.sensoroni.config.sensoronikey}) %} +{% do SOCDEFAULTS.soc.config.server.modules.statickeyauth.update({'anonymousCidr': DOCKERMERGED.range, 'apiKey': pillar.sensoroni.config.sensoronikey}) %} {% do SOCDEFAULTS.soc.config.server.client.case.update({'analyzerNodeId': GLOBALS.hostname}) %} {% do SOCDEFAULTS.soc.config.server.client.update({'exportNodeId': GLOBALS.hostname}) %} diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 28db2ef5f..0bde8f20e 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -115,16 +115,16 @@ soc: ':kratos:': - soc_timestamp - event.dataset - - http_request.headers.x-real-ip + - http.request.headers.x-real-ip - user.name - - http_request.headers.user-agent + - http.useragent - msg ':hydra:': - soc_timestamp - event.dataset - - http_request.headers.x-real-ip + - http.request.headers.x-real-ip - user.name - - http_request.headers.user-agent + - http.useragent - msg '::conn': - soc_timestamp @@ -584,6 +584,18 @@ soc: - destination.port - event.action - tunnel.type + '::websocket': + - soc_timestamp + - event.dataset + - source.ip + - source.port + - destination.ip + - destination.port + - websocket.host + - websocket.uri + - websocket.user_agent + - log.id.uid + - network.community_id '::weird': - soc_timestamp - event.dataset @@ -1494,10 +1506,19 @@ soc: branch: main folder: securityonion-normalized assistant: - apiUrl: https://onionai.securityonion.net - healthTimeoutSeconds: 3 systemPromptAddendum: "" systemPromptAddendumMaxLength: 50000 + adapters: + - name: SOAI + protocol: securityonion_ai_cloud + apiUrl: https://onionai.securityonion.net + healthTimeoutSeconds: 5 + - name: Gemini + protocol: gemini + apiKey: "" + serviceAccountJSON: "" + serviceAccountLocation: "" + healthTimeoutSeconds: 5 salt: queueDir: /opt/sensoroni/queue timeoutMs: 45000 @@ -1509,6 +1530,7 @@ soc: anonymousCidr: apiKey: staticrbac: + defaultRole: "" roleFiles: - rbac/permissions - rbac/roles @@ -1622,7 +1644,7 @@ soc: sourceType: directory airgap: - name: Emerging-Threats - description: "Emerging Threats ruleset - To enable ET Pro on Airgap, review the documentation at https://docs.securityonion.net/suricata" + description: "Emerging Threats ruleset - To enable ET Pro on Airgap, review the documentation at https://securityonion.net/docs/suricata" licenseKey: "" enabled: true sourceType: directory @@ -1669,8 +1691,8 @@ soc: client: docsUrl: /docs/ cheatsheetUrl: /docs/cheatsheet.pdf - releaseNotesUrl: /docs/release-notes.html - apiTimeoutMs: 300000 + releaseNotesUrl: /docs/release-notes + apiTimeoutMs: webSocketTimeoutMs: 15000 tipTimeoutMs: 6000 cacheExpirationMs: 300000 @@ -1747,7 +1769,7 @@ soc: showSubtitle: true - name: SOC - Auth description: Users authenticated to SOC grouped by IP address and identity - query: 'event.dataset:kratos.audit AND msg:*authenticated* | groupby http_request.headers.x-real-ip user.name' + query: 'event.dataset:kratos.audit AND msg:*authenticated* | groupby http.request.headers.x-real-ip user.name' showSubtitle: true - name: SOC - App description: Logs generated by the Security Onion Console (SOC) server and modules @@ -2027,10 +2049,10 @@ soc: query: '* | groupby event.category | groupby -sankey event.category event.module | groupby event.module | groupby -sankey event.module event.dataset | groupby event.dataset | groupby observer.name | groupby host.name | groupby source.ip | groupby destination.ip | groupby destination.port' - name: SOC Logins description: SOC (Security Onion Console) logins - query: 'event.dataset:kratos.audit AND msg:*authenticated* | groupby http_request.headers.x-real-ip | groupby -sankey http_request.headers.x-real-ip user.name | groupby user.name | groupby http_request.headers.user-agent' + query: 'event.dataset:kratos.audit AND msg:*authenticated* | groupby http.request.headers.x-real-ip | groupby -sankey http.request.headers.x-real-ip user.name | groupby user.name | groupby http.useragent' - name: SOC Login Failures description: SOC (Security Onion Console) login failures - query: 'event.dataset:kratos.audit AND msg:*Encountered*self-service*login*error* | groupby user.name | groupby http_request.headers.x-real-ip | groupby -sankey http_request.headers.x-real-ip http_request.headers.user-agent | groupby http_request.headers.user-agent' + query: 'event.dataset:kratos.audit AND msg:*Encountered*self-service*login*error* | groupby user.name | groupby http.request.headers.x-real-ip | groupby -sankey http.request.headers.x-real-ip http.useragent | groupby http.useragent' - name: Alerts description: Overview of all alerts query: 'tags:alert | groupby event.module* | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby rule.name | groupby event.severity | groupby destination.as.organization.name' @@ -2370,6 +2392,10 @@ soc: exclusive: true enablesToggles: - acknowledged + - name: investigated + filter: event.investigated:true + enabled: false + exclusive: false queries: - name: 'Group By Name, Module' query: '* | groupby rule.name event.module* event.severity_label rule.uuid' @@ -2596,6 +2622,7 @@ soc: This is a YARA rule template. Replace all template values with your own values. The YARA rule name is the unique identifier for the rule. Docs: https://yara.readthedocs.io/en/stable/writingrules.html#writing-yara-rules + Delete these comments before attempting to "Create" the rule */ rule Example // This identifier _must_ be unique @@ -2652,17 +2679,12 @@ soc: thresholdColorRatioMed: 0.75 thresholdColorRatioMax: 1 availableModels: - - id: sonnet-4.5 - displayName: Claude Sonnet 4.5 ($$$) + - id: sonnet + displayName: Claude Sonnet origin: USA contextLimitSmall: 200000 contextLimitLarge: 1000000 lowBalanceColorAlert: 500000 enabled: true - - id: qwen-235b - displayName: QWEN 235B ($) - origin: China - contextLimitSmall: 256000 - contextLimitLarge: 256000 - lowBalanceColorAlert: 500000 - enabled: true + adapter: SOAI + diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls index 62e673ffc..1805bacaf 100644 --- a/salt/soc/enabled.sls +++ b/salt/soc/enabled.sls @@ -6,11 +6,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'soc/merged.map.jinja' import DOCKER_EXTRA_HOSTS %} {% from 'soc/merged.map.jinja' import SOCMERGED %} include: + - ca - soc.config - soc.sostatus @@ -21,7 +22,7 @@ so-soc: - name: so-soc - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-soc'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-soc'].ip }} - binds: - /nsm/rules:/nsm/rules:rw - /opt/so/conf/strelka:/opt/sensoroni/yara:rw @@ -55,31 +56,39 @@ so-soc: - /opt/so/conf/soc/migrations:/opt/so/conf/soc/migrations:rw - /nsm/backup/detections-migration:/nsm/backup/detections-migration:ro - /opt/so/state:/opt/so/state:rw - - /etc/pki/ca.crt:/opt/sensoroni/html/so-ca.crt:ro + - /etc/pki/tls/certs/intca.crt:/opt/sensoroni/html/so-ca.crt:ro - extra_hosts: {% for node in DOCKER_EXTRA_HOSTS %} {% for hostname, ip in node.items() %} - {{hostname}}:{{ip}} {% endfor %} {% endfor %} - {% if DOCKER.containers['so-soc'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-soc'].extra_hosts %} + {% if DOCKERMERGED.containers['so-soc'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-soc'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-soc'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-soc'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-soc'].extra_env %} + {% if DOCKERMERGED.containers['so-soc'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-soc'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-soc'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-soc'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-soc'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: + - file: trusttheca - file: /opt/so/conf/soc/* - require: + - file: trusttheca - file: socdatadir - file: soclogdir - file: socconfig diff --git a/salt/soc/files/soc/motd.md b/salt/soc/files/soc/motd.md index 69b3145fa..9d1e2fb1d 100644 --- a/salt/soc/files/soc/motd.md +++ b/salt/soc/files/soc/motd.md @@ -18,7 +18,7 @@ For more coverage of your enterprise, you can deploy the Elastic Agent to endpoi ## What's New -To see all the latest features and fixes in this version of Security Onion, click the upper-right menu and then click the [What's New](/docs/release-notes.html) link. +To see all the latest features and fixes in this version of Security Onion, click the upper-right menu and then click the [What's New](/docs/release-notes) link. ## Security Onion Pro diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 11442afba..c5f96894d 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -1,12 +1,14 @@ soc: enabled: description: Enables or disables SOC. WARNING - Disabling this setting is unsupported and will cause the grid to malfunction. Re-enabling this setting is a manual effort via SSH. + forcedType: bool advanced: True telemetryEnabled: title: SOC Telemetry description: When this setting is enabled and the grid is not in airgap mode, SOC will provide feature usage data to the Security Onion development team via Google Analytics. This data helps Security Onion developers determine which product features are being used and can also provide insight into improving the user interface. When changing this setting, wait for the grid to fully synchronize and then perform a hard browser refresh on SOC, to force the browser cache to update and reflect the new setting. global: True - helpLink: telemetry.html + helpLink: telemetry + forcedType: bool files: soc: banner__md: @@ -15,28 +17,28 @@ soc: file: True global: True syntax: md - helpLink: soc-customization.html + helpLink: security-onion-console-customization motd__md: title: Overview Page description: Customize the overview page with specific markdown-formatted content. Images can be used but must be hosted from another host that is accessible by the user's browser. file: True global: True syntax: md - helpLink: soc-customization.html + helpLink: security-onion-console-customization custom__js: title: Custom Javascript description: Customize SOC UI behavior with custom Javascript code. Custom Javascript not provided by Security Onion Solutions is unsupported, and should be removed prior to requesting support and prior to performing upgrades. file: True global: True advanced: True - helpLink: soc-customization.html + helpLink: security-onion-console-customization custom_roles: title: Custom Roles description: Customize role and permission mappings. Changing this setting requires a complete understanding of the SOC RBAC system. file: True global: True advanced: True - helpLink: soc-customization.html + helpLink: security-onion-console-customization sigma_final_pipeline__yaml: title: Final Sigma Pipeline description: Final Processing Pipeline for Sigma Rules. @@ -44,7 +46,7 @@ soc: file: True global: True advanced: True - helpLink: soc-customization.html + helpLink: security-onion-console-customization config: licenseKey: title: License Key @@ -138,6 +140,7 @@ soc: title: Require TOTP description: Require all users to enable Time-based One Time Passwords (MFA) upon login to SOC. global: True + forcedType: bool customReportsPath: title: Custom Reports Path description: Path to custom markdown templates for PDF report generation. All markdown files in this directory will be available as custom reports in the SOC Reports interface. @@ -183,7 +186,8 @@ soc: enableReverseLookup: description: "Set to true to enable reverse DNS lookups for IP addresses in the SOC UI. To add your own local lookups, create a CSV file at /nsm/custom-mappings/ip-descriptions.csv on your Manager and populate the file with IP addresses and descriptions as follows: IP, Description. Elasticsearch will then ingest the CSV during the next high state." global: True - helpLink: soc-customization.html#reverse-dns + helpLink: security-onion-console-customization#reverse-dns + forcedType: bool modules: elastalertengine: aiRepoUrl: @@ -201,11 +205,12 @@ soc: showAiSummaries: description: Show AI summaries for ElastAlert rules. global: True + forcedType: bool additionalAlerters: title: "Notifications: Sev 0/Default Alerters" description: "Specify default alerters to enable for outbound notifications. These alerters will be used unless overridden by higher severity alerter settings. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" multiline: True additionalSev0AlertersParams: @@ -214,14 +219,14 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications forcedType: string jinjaEscaped: True additionalSev1Alerters: title: "Notifications: Sev 1/Informational Alerters" description: "Specify specific alerters to use when alerting at the info severity level or higher. These alerters will be used unless overridden by higher severity alerter settings. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" multiline: True additionalSev1AlertersParams: @@ -230,14 +235,14 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications forcedType: string jinjaEscaped: True additionalSev2Alerters: title: "Notifications: Sev 2/Low Alerters" description: "Specify specific alerters to use when alerting at the low severity level or higher. These alerters will be used unless overridden by higher severity alerter settings. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" multiline: True additionalSev2AlertersParams: @@ -246,14 +251,14 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications forcedType: string jinjaEscaped: True additionalSev3Alerters: title: "Notifications: Sev 3/Medium Alerters" description: "Specify specific alerters to use when alerting at the medium severity level or higher. These alerters will be used unless overridden by higher severity alerter settings. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" multiline: True additionalSev3AlertersParams: @@ -262,14 +267,14 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications forcedType: string jinjaEscaped: True additionalSev4Alerters: title: "Notifications: Sev 4/High Alerters" description: "Specify specific alerters to use when alerting at the high severity level or critical severity level. These alerters will be used unless overridden by critical severity alerter settings. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" multiline: True additionalSev4AlertersParams: @@ -278,14 +283,14 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications forcedType: string jinjaEscaped: True additionalSev5Alerters: title: "Notifications: Sev 5/Critical Alerters" description: "Specify specific alerters to use when alerting at the critical severity level. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" multiline: True additionalSev5AlertersParams: @@ -294,14 +299,14 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications forcedType: string jinjaEscaped: True additionalUserDefinedNotifications: customAlerters: description: "Specify custom notification alerters to use when the Sigma rule contains the following tag: so.alerters.customAlerters. This setting can be duplicated to create new custom alerter configurations. Specify one alerter name (Ex: 'email') per line. Alerters refers to ElastAlert 2 alerters, as documented at https://elastalert2.readthedocs.io. A full update of the ElastAlert rule engine, via the Detections screen, is required in order to apply these changes. Requires a valid Security Onion license key." global: True - helpLink: notifications.html + helpLink: notifications forcedType: "[]string" duplicates: True multiline: True @@ -310,7 +315,7 @@ soc: global: True multiline: True syntax: yaml - helpLink: notifications.html + helpLink: notifications duplicates: True forcedType: string jinjaEscaped: True @@ -318,7 +323,7 @@ soc: default: &enabledSigmaRules description: 'Sigma rules to automatically enable on initial import. The format is a YAML list, with the ability to filter for ruleset, level, product, category and service. Refer to the documentation for further details. These will be applied based on role if defined and default if not.' global: True - helpLink: sigma.html + helpLink: sigma multiline: True syntax: yaml forcedType: string @@ -330,18 +335,19 @@ soc: description: 'DEPRECATED: Will be removed in a future release - use enabledSigmaRules instead.' global: True advanced: True - helpLink: sigma.html + helpLink: sigma so-eval: *autoEnabledSigmaRules so-import: *autoEnabledSigmaRules autoUpdateEnabled: description: 'Automatically update Sigma rules on a regular basis. This will update the rules based on the configured frequency.' global: True advanced: True + forcedType: bool communityRulesImportFrequencySeconds: description: 'How often to check for new Sigma rules (in seconds). This applies to both Community Rule Packages and any configured Git repos.' global: True advanced: True - helpLink: sigma.html + helpLink: sigma integrityCheckFrequencySeconds: description: 'How often the ElastAlert integrity checker runs (in seconds). This verifies the integrity of deployed rules.' global: True @@ -352,7 +358,7 @@ soc: global: True advanced: True forcedType: "[]{}" - helpLink: sigma.html + helpLink: sigma syntax: json uiElements: - field: rulesetName @@ -375,7 +381,7 @@ soc: description: 'Defines the Sigma Community Ruleset you want to run. One of these (core | core+ | core++ | all ) as well as an optional Add-on (emerging_threats_addon). Once you have changed the ruleset here, the new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Elastalert --> Full Update. WARNING! Changing the ruleset will remove all existing non-overlapping Sigma rules of the previous ruleset and their associated overrides. This removal cannot be undone.' global: True advanced: False - helpLink: sigma.html + helpLink: sigma elastic: index: description: Comma-separated list of indices or index patterns (wildcard "*" supported) that SOC will search for records. @@ -394,6 +400,7 @@ soc: description: Set to true if the SOC case management module, natively integrated with Elasticsearch, should be enabled. global: True advanced: True + forcedType: bool extractCommonObservables: description: List of indexed fields to automatically extract into a case observable, when attaching related events to a case. global: True @@ -420,6 +427,7 @@ soc: lookupTunnelParent: description: When true, if a pivoted event appears to be encapsulated, such as in a VXLAN packet, then SOC will pivot to the VXLAN packet stream. When false, SOC will attempt to pivot to the encapsulated packet stream itself, but at the risk that it may be unable to locate it in the stored PCAP data. global: True + forcedType: bool maxScrollSize: description: The maximum number of documents to request in a single Elasticsearch scroll request. bulkIndexWorkerCount: @@ -455,6 +463,11 @@ soc: global: True advanced: True forcedType: int + staticrbac: + defaultRole: + description: "Default role for new users that have not been assigned a role. When a role is specified, an attempt will be made to permanently assign the role to the user once the user accesses SOC. The role name must match exactly the name of an existing RBAC role. Standard system roles include: limited-auditor, limited-analyst, auditor, analyst, superuser" + global: True + advanced: False strelkaengine: aiRepoUrl: description: URL to the AI repository. This is used to pull in AI models for use in Strelka rules. @@ -471,20 +484,22 @@ soc: showAiSummaries: description: Show AI summaries for Strelka rules. global: True + forcedType: bool autoUpdateEnabled: description: 'Automatically update YARA rules on a regular basis. This will update the rules based on the configured frequency.' global: True advanced: True + forcedType: bool autoEnabledYaraRules: description: 'YARA rules to automatically enable on initial import. Format is $Ruleset - for example, for the default shipped ruleset: securityonion-yara' global: True advanced: True - helpLink: sigma.html + helpLink: sigma communityRulesImportFrequencySeconds: description: 'How often to check for new YARA rules (in seconds). This applies to both Community Rules and any configured Git repos.' global: True advanced: True - helpLink: yara.html + helpLink: yara integrityCheckFrequencySeconds: description: 'How often the Strelka integrity checker runs (in seconds). This verifies the integrity of deployed rules.' global: True @@ -495,7 +510,7 @@ soc: global: True advanced: True forcedType: "[]{}" - helpLink: yara.html + helpLink: yara syntax: json uiElements: - field: rulesetName @@ -530,15 +545,17 @@ soc: showAiSummaries: description: Show AI summaries for Suricata rules. global: True + forcedType: bool autoUpdateEnabled: description: 'Automatically update Suricata rules on a regular basis. This will update the rules based on the configured frequency.' global: True advanced: True + forcedType: bool communityRulesImportFrequencySeconds: description: 'How often to check for new Suricata rules (in seconds).' global: True advanced: True - helpLink: suricata.html + helpLink: suricata disableRegex: description: A list of regular expressions used to automatically disable rules that match any of them. Each regular expression is tested against the rule's content. global: True @@ -552,24 +569,25 @@ soc: global: True advanced: True customRulesets: - description: 'URLs and/or Local File configurations for Suricata custom rulesets. Refer to the linked documentation for important specification and file placement information' + description: 'This setting is no longer used. Use Ruleset Sources setting instead.' global: True advanced: True forcedType: "[]{}" - helpLink: suricata.html + readonly: True + helpLink: suricata ignoredSidRanges: description: 'List of Suricata SID ranges to ignore during the Integrity Check. This is useful for ignoring specific rules not governed by the UI. Each line should contain 1 range in the format "1100000-1200000". The ranges are treated as inclusive.' global: True advanced: True forcedType: "[]string" - helpLink: detections.html#rule-engine-status + helpLink: detections#rule-engine-status rulesetSources: default: &serulesetSources description: "Ruleset sources for Suricata rules. Supports URL downloads and local directories. Refer to the linked documentation for details on how to configure this setting." global: True advanced: False forcedType: "[]{}" - helpLink: suricata.html + helpLink: suricata syntax: json uiElements: - field: name @@ -625,11 +643,11 @@ soc: intervalMinutes: description: How often to generate the Navigator Layers. (minutes) global: True - helpLink: attack-navigator.html + helpLink: attack-navigator lookbackDays: description: How far back to search for ATT&CK-tagged alerts. (days) global: True - helpLink: attack-navigator.html + helpLink: attack-navigator playbook: playbookRepos: default: &pbRepos @@ -650,14 +668,6 @@ soc: label: Folder airgap: *pbRepos assistant: - apiUrl: - description: The URL of the AI gateway. - advanced: True - global: True - healthTimeoutSeconds: - description: Timeout in seconds for the Onion AI health check. - global: True - advanced: True systemPromptAddendum: description: Additional context to provide to the AI assistant about this SOC deployment. This can include information about your environment, policies, or any other relevant details that can help the AI provide more accurate and tailored assistance. Long prompts may be shortened. global: True @@ -667,11 +677,50 @@ soc: description: Maximum length of the system prompt addendum. Longer prompts will be truncated. global: True advanced: True + adapters: + description: Configuration for AI adapters used by the Onion AI assistant. Please see documentation for help on which fields are required for which protocols. + global: True + advanced: False + forcedType: "[]{}" + helpLink: onion-ai + syntax: json + uiElements: + - field: name + label: Adapter Name + regex: "^(?!.*@).+$" + regexFailureMessage: Adapter name cannot contain the '@' character + required: True + - field: protocol + label: Protocol + required: True + options: + - securityonion_ai_cloud + - gemini + - openai_responses + - openai_chat + - field: apiUrl + label: API URL + required: False + - field: apiKey + label: API Key + required: False + - field: serviceAccountJSON + label: Service Account JSON + required: False + multiline: True + - field: serviceAccountLocation + label: Service Account Location + required: False + - field: healthTimeoutSeconds + label: Health Timeout Seconds + required: False + forcedType: int client: assistant: enabled: description: Set to true to enable the Onion AI assistant in SOC. global: True + forcedType: bool investigationPrompt: description: Prompt given to Onion AI when beginning an investigation. global: True @@ -697,14 +746,16 @@ soc: availableModels: description: List of AI models available for use in SOC as well as model specific warning thresholds. global: True - advanced: True + advanced: False forcedType: "[]{}" - helpLink: assistant.html + helpLink: onion-ai syntax: json uiElements: - field: id label: Model ID required: True + regex: "^(?!.*@).+$" + regexFailureMessage: Model ID cannot contain the '@' character - field: displayName label: Display Name required: True @@ -722,6 +773,8 @@ soc: - field: lowBalanceColorAlert label: Low Balance Color Alert forcedType: int + - field: adapter + label: Adapter required: True - field: enabled label: Enabled @@ -748,9 +801,11 @@ soc: casesEnabled: description: Set to true to enable case management in SOC. global: True + forcedType: bool detectionsEnabled: description: Set to true to enable the Detections module in SOC. global: True + forcedType: bool inactiveTools: description: List of external tools to remove from the SOC UI. global: True @@ -826,6 +881,7 @@ soc: showUnreviewedAiSummaries: description: Show AI summaries in detections even if they have not yet been reviewed by a human. global: True + forcedType: bool templateDetections: suricata: description: The template used when creating a new Suricata detection. [publicId] will be replaced with an unused Public Id. @@ -863,6 +919,7 @@ soc: customEnabled: description: Set to true to allow users add their own artifact types directly in the SOC UI. global: True + forcedType: bool category: labels: description: List of available case categories. @@ -870,6 +927,7 @@ soc: customEnabled: description: Set to true to allow users add their own categories directly in the SOC UI. global: True + forcedType: bool pap: labels: description: List of available PAP (Permissible Actions Protocol) values. @@ -877,6 +935,7 @@ soc: customEnabled: description: Set to true to allow users add their own PAP values directly in the SOC UI. global: True + forcedType: bool severity: labels: description: List of available case severities. @@ -884,6 +943,7 @@ soc: customEnabled: description: Set to true to allow users add their own severities directly in the SOC UI. global: True + forcedType: bool status: labels: description: List of available case statuses. Note that some default statuses have special characteristics and related functionality built into SOC. @@ -891,6 +951,7 @@ soc: customEnabled: description: Set to true to allow users add their own case statuses directly in the SOC UI. global: True + forcedType: bool tags: labels: description: List of available tags. @@ -898,6 +959,7 @@ soc: customEnabled: description: Set to true to allow users add their own tags directly in the SOC UI. global: True + forcedType: bool tlp: labels: description: List of available TLP (Traffic Light Protocol) values. @@ -905,3 +967,4 @@ soc: customEnabled: description: Set to true to allow users add their own TLP values directly in the SOC UI. global: True + forcedType: bool diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls deleted file mode 100644 index 0cef8c1e3..000000000 --- a/salt/ssl/init.sls +++ /dev/null @@ -1,720 +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 %} - -{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} - -{% set global_ca_text = [] %} -{% set global_ca_server = [] %} -{% if grains.role in ['so-heavynode'] %} - {% set COMMONNAME = GLOBALS.hostname %} -{% else %} - {% set COMMONNAME = GLOBALS.manager %} -{% endif %} - -{% if GLOBALS.is_manager %} -include: - - ca - {% set trusttheca_text = salt['cp.get_file_str']('/etc/pki/ca.crt')|replace('\n', '') %} - {% set ca_server = grains.id %} -{% else %} -include: - - ca.dirs - {% set x509dict = salt['mine.get'](GLOBALS.manager | lower~'*', 'x509.get_pem_entries') %} - {% for host in x509dict %} - {% if 'manager' in host.split('_')|last or host.split('_')|last == 'standalone' %} - {% 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] %} -{% endif %} - -cacertdir: - file.directory: - - name: /etc/pki/tls/certs - - makedirs: True - -# Trust the CA -trusttheca: - x509.pem_managed: - - name: /etc/pki/tls/certs/intca.crt - - text: {{ trusttheca_text }} - -{% if GLOBALS.os_family == 'Debian' %} -symlinkca: - file.symlink: - - target: /etc/pki/tls/certs/intca.crt - - name: /etc/ssl/certs/intca.crt -{% endif %} - -# Install packages needed for the sensor -m2cryptopkgs: - pkg.installed: - - skip_suggestions: False - - pkgs: - - python3-m2crypto - -influxdb_key: - x509.private_key_managed: - - name: /etc/pki/influxdb.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/influxdb.key') -%} - - prereq: - - x509: /etc/pki/influxdb.crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -# Create a cert for the talking to influxdb -influxdb_crt: - x509.certificate_managed: - - name: /etc/pki/influxdb.crt - - ca_server: {{ ca_server }} - - signing_policy: influxdb - - private_key: /etc/pki/influxdb.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - -influxkeyperms: - file.managed: - - replace: False - - name: /etc/pki/influxdb.key - - mode: 640 - - group: 939 - -{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %} -# Create a cert for Redis encryption -redis_key: - x509.private_key_managed: - - name: /etc/pki/redis.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/redis.key') -%} - - prereq: - - x509: /etc/pki/redis.crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -redis_crt: - x509.certificate_managed: - - name: /etc/pki/redis.crt - - ca_server: {{ ca_server }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - signing_policy: registry - - private_key: /etc/pki/redis.key - - CN: {{ GLOBALS.hostname }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - -rediskeyperms: - file.managed: - - replace: False - - name: /etc/pki/redis.key - - mode: 640 - - group: 939 -{% endif %} - -{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-fleet', 'so-receiver'] %} - -{% if grains['role'] not in [ 'so-heavynode', 'so-receiver'] %} -# Start -- Elastic Fleet Host Cert -etc_elasticfleet_key: - x509.private_key_managed: - - name: /etc/pki/elasticfleet-server.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticfleet-server.key') -%} - - prereq: - - x509: etc_elasticfleet_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -etc_elasticfleet_crt: - x509.certificate_managed: - - name: /etc/pki/elasticfleet-server.crt - - ca_server: {{ ca_server }} - - signing_policy: elasticfleet - - private_key: /etc/pki/elasticfleet-server.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }},DNS:{{ GLOBALS.url_base }},IP:{{ GLOBALS.node_ip }}{% if ELASTICFLEETMERGED.config.server.custom_fqdn | length > 0 %},DNS:{{ ELASTICFLEETMERGED.config.server.custom_fqdn | join(',DNS:') }}{% endif %} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - -efperms: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-server.key - - mode: 640 - - group: 939 - -chownelasticfleetcrt: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-server.crt - - mode: 640 - - user: 947 - - group: 939 - -chownelasticfleetkey: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-server.key - - mode: 640 - - user: 947 - - group: 939 -# End -- Elastic Fleet Host Cert -{% endif %} # endif is for not including HeavyNodes & Receivers - -{% if grains['role'] not in [ 'so-heavynode'] %} -# Start -- Elastic Fleet Logstash Input Cert -etc_elasticfleet_logstash_key: - x509.private_key_managed: - - name: /etc/pki/elasticfleet-logstash.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticfleet-logstash.key') -%} - - prereq: - - x509: etc_elasticfleet_logstash_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -etc_elasticfleet_logstash_crt: - x509.certificate_managed: - - name: /etc/pki/elasticfleet-logstash.crt - - ca_server: {{ ca_server }} - - signing_policy: elasticfleet - - private_key: /etc/pki/elasticfleet-logstash.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }},DNS:{{ GLOBALS.url_base }},IP:{{ GLOBALS.node_ip }}{% if ELASTICFLEETMERGED.config.server.custom_fqdn | length > 0 %},DNS:{{ ELASTICFLEETMERGED.config.server.custom_fqdn | join(',DNS:') }}{% endif %} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-logstash.key -topk8 -out /etc/pki/elasticfleet-logstash.p8 -nocrypt" - - onchanges: - - x509: etc_elasticfleet_logstash_key - -eflogstashperms: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-logstash.key - - mode: 640 - - group: 939 - -chownelasticfleetlogstashcrt: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-logstash.crt - - mode: 640 - - user: 931 - - group: 939 - -chownelasticfleetlogstashkey: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-logstash.key - - mode: 640 - - user: 931 - - group: 939 -# End -- Elastic Fleet Logstash Input Cert -{% endif %} # endif is for not including HeavyNodes - -# Start -- Elastic Fleet Node - Logstash Lumberjack Input / Output -# Cert needed on: Managers, Receivers -etc_elasticfleetlumberjack_key: - x509.private_key_managed: - - name: /etc/pki/elasticfleet-lumberjack.key - - bits: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticfleet-lumberjack.key') -%} - - prereq: - - x509: etc_elasticfleetlumberjack_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -etc_elasticfleetlumberjack_crt: - x509.certificate_managed: - - name: /etc/pki/elasticfleet-lumberjack.crt - - ca_server: {{ ca_server }} - - signing_policy: elasticfleet - - private_key: /etc/pki/elasticfleet-lumberjack.key - - CN: {{ GLOBALS.node_ip }} - - subjectAltName: DNS:{{ GLOBALS.hostname }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-lumberjack.key -topk8 -out /etc/pki/elasticfleet-lumberjack.p8 -nocrypt" - - onchanges: - - x509: etc_elasticfleetlumberjack_key - -eflogstashlumberjackperms: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-lumberjack.key - - mode: 640 - - group: 939 - -chownilogstashelasticfleetlumberjackp8: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-lumberjack.p8 - - mode: 640 - - user: 931 - - group: 939 - -chownilogstashelasticfleetlogstashlumberjackcrt: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-lumberjack.crt - - mode: 640 - - user: 931 - - group: 939 - -chownilogstashelasticfleetlogstashlumberjackkey: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-lumberjack.key - - mode: 640 - - user: 931 - - group: 939 - -# End -- Elastic Fleet Node - Logstash Lumberjack Input / Output - -# Start -- Elastic Fleet Client Cert for Agent (Mutual Auth with Logstash Output) -etc_elasticfleet_agent_key: - x509.private_key_managed: - - name: /etc/pki/elasticfleet-agent.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticfleet-agent.key') -%} - - prereq: - - x509: etc_elasticfleet_agent_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -etc_elasticfleet_agent_crt: - x509.certificate_managed: - - name: /etc/pki/elasticfleet-agent.crt - - ca_server: {{ ca_server }} - - signing_policy: elasticfleet - - private_key: /etc/pki/elasticfleet-agent.key - - CN: {{ GLOBALS.hostname }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs8 -in /etc/pki/elasticfleet-agent.key -topk8 -out /etc/pki/elasticfleet-agent.p8 -nocrypt" - - onchanges: - - x509: etc_elasticfleet_agent_key - -efagentperms: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-agent.key - - mode: 640 - - group: 939 - -chownelasticfleetagentcrt: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-agent.crt - - mode: 640 - - user: 947 - - group: 939 - -chownelasticfleetagentkey: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-agent.key - - mode: 640 - - user: 947 - - group: 939 -# End -- Elastic Fleet Client Cert for Agent (Mutual Auth with Logstash Output) - -{% endif %} - -{% if GLOBALS.is_manager or GLOBALS.role in ['so-heavynode', 'so-receiver'] %} -etc_filebeat_key: - x509.private_key_managed: - - name: /etc/pki/filebeat.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/filebeat.key') -%} - - prereq: - - x509: etc_filebeat_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -# Request a cert and drop it where it needs to go to be distributed -etc_filebeat_crt: - x509.certificate_managed: - - name: /etc/pki/filebeat.crt - - ca_server: {{ ca_server }} - - signing_policy: filebeat - - private_key: /etc/pki/filebeat.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs8 -in /etc/pki/filebeat.key -topk8 -out /etc/pki/filebeat.p8 -nocrypt" - - onchanges: - - x509: etc_filebeat_key - -fbperms: - file.managed: - - replace: False - - name: /etc/pki/filebeat.key - - mode: 640 - - group: 939 - -chownilogstashfilebeatp8: - file.managed: - - replace: False - - name: /etc/pki/filebeat.p8 - - mode: 640 - - user: 931 - - group: 939 - - {% if grains.role not in ['so-heavynode', 'so-receiver'] %} -# Create Symlinks to the keys so I can distribute it to all the things -filebeatdir: - file.directory: - - name: /opt/so/saltstack/local/salt/filebeat/files - - makedirs: True - -fbkeylink: - file.symlink: - - name: /opt/so/saltstack/local/salt/filebeat/files/filebeat.p8 - - target: /etc/pki/filebeat.p8 - - user: socore - - group: socore - -fbcrtlink: - file.symlink: - - name: /opt/so/saltstack/local/salt/filebeat/files/filebeat.crt - - target: /etc/pki/filebeat.crt - - user: socore - - group: socore - -registry_key: - x509.private_key_managed: - - name: /etc/pki/registry.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/registry.key') -%} - - prereq: - - x509: /etc/pki/registry.crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -# Create a cert for the docker registry -registry_crt: - x509.certificate_managed: - - name: /etc/pki/registry.crt - - ca_server: {{ ca_server }} - - subjectAltName: DNS:{{ GLOBALS.manager }}, IP:{{ GLOBALS.manager_ip }} - - signing_policy: registry - - private_key: /etc/pki/registry.key - - CN: {{ GLOBALS.manager }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - -regkeyperms: - file.managed: - - replace: False - - name: /etc/pki/registry.key - - mode: 640 - - group: 939 - - {% endif %} - {% if grains.role not in ['so-receiver'] %} -# Create a cert for elasticsearch -/etc/pki/elasticsearch.key: - x509.private_key_managed: - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticsearch.key') -%} - - prereq: - - x509: /etc/pki/elasticsearch.crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -/etc/pki/elasticsearch.crt: - x509.certificate_managed: - - ca_server: {{ ca_server }} - - signing_policy: registry - - private_key: /etc/pki/elasticsearch.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/elasticsearch.key -in /etc/pki/elasticsearch.crt -export -out /etc/pki/elasticsearch.p12 -nodes -passout pass:" - - onchanges: - - x509: /etc/pki/elasticsearch.key - -elastickeyperms: - file.managed: - - replace: False - - name: /etc/pki/elasticsearch.key - - mode: 640 - - group: 930 - -elasticp12perms: - file.managed: - - replace: False - - name: /etc/pki/elasticsearch.p12 - - mode: 640 - - group: 930 - - {% endif %} - - -{% endif %} - -{% if GLOBALS.is_manager or GLOBALS.role in ['so-sensor', 'so-searchnode', 'so-heavynode', 'so-fleet', 'so-idh', 'so-receiver'] %} - -fbcertdir: - file.directory: - - name: /opt/so/conf/filebeat/etc/pki - - makedirs: True - -conf_filebeat_key: - x509.private_key_managed: - - name: /opt/so/conf/filebeat/etc/pki/filebeat.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/opt/so/conf/filebeat/etc/pki/filebeat.key') -%} - - prereq: - - x509: conf_filebeat_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -# Request a cert and drop it where it needs to go to be distributed -conf_filebeat_crt: - x509.certificate_managed: - - name: /opt/so/conf/filebeat/etc/pki/filebeat.crt - - ca_server: {{ ca_server }} - - signing_policy: filebeat - - private_key: /opt/so/conf/filebeat/etc/pki/filebeat.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - -# Convert the key to pkcs#8 so logstash will work correctly. -filebeatpkcs: - cmd.run: - - name: "/usr/bin/openssl pkcs8 -in /opt/so/conf/filebeat/etc/pki/filebeat.key -topk8 -out /opt/so/conf/filebeat/etc/pki/filebeat.p8 -passout pass:" - - onchanges: - - x509: conf_filebeat_key - -filebeatkeyperms: - file.managed: - - replace: False - - name: /opt/so/conf/filebeat/etc/pki/filebeat.key - - mode: 640 - - group: 939 - -chownfilebeatp8: - file.managed: - - replace: False - - name: /opt/so/conf/filebeat/etc/pki/filebeat.p8 - - mode: 640 - - user: 931 - - group: 939 - -{% endif %} - -{% if grains['role'] == 'so-searchnode' %} -# Create a cert for elasticsearch -/etc/pki/elasticsearch.key: - x509.private_key_managed: - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticsearch.key') -%} - - prereq: - - x509: /etc/pki/elasticsearch.crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -/etc/pki/elasticsearch.crt: - x509.certificate_managed: - - ca_server: {{ ca_server }} - - signing_policy: registry - - private_key: /etc/pki/elasticsearch.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - cmd.run: - - name: "/usr/bin/openssl pkcs12 -inkey /etc/pki/elasticsearch.key -in /etc/pki/elasticsearch.crt -export -out /etc/pki/elasticsearch.p12 -nodes -passout pass:" - - onchanges: - - x509: /etc/pki/elasticsearch.key - -elasticp12perms: - file.managed: - - replace: False - - name: /etc/pki/elasticsearch.p12 - - mode: 640 - - group: 930 - -elastickeyperms: - file.managed: - - replace: False - - name: /etc/pki/elasticsearch.key - - mode: 640 - - group: 930 -{%- endif %} - -{% if GLOBALS.role in ['so-manager', 'so-managerhype', 'so-managersearch', 'so-standalone'] %} -elasticfleet_kafka_key: - x509.private_key_managed: - - name: /etc/pki/elasticfleet-kafka.key - - keysize: 4096 - - backup: True - - new: True - {% if salt['file.file_exists']('/etc/pki/elasticfleet-kafka.key') -%} - - prereq: - - x509: elasticfleet_kafka_crt - {%- endif %} - - retry: - attempts: 5 - interval: 30 - -elasticfleet_kafka_crt: - x509.certificate_managed: - - name: /etc/pki/elasticfleet-kafka.crt - - ca_server: {{ ca_server }} - - signing_policy: kafka - - private_key: /etc/pki/elasticfleet-kafka.key - - CN: {{ GLOBALS.hostname }} - - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} - - days_remaining: 0 - - days_valid: 820 - - backup: True - - timeout: 30 - - retry: - attempts: 5 - interval: 30 - -elasticfleet_kafka_cert_perms: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-kafka.crt - - mode: 640 - - user: 947 - - group: 939 - -elasticfleet_kafka_key_perms: - file.managed: - - replace: False - - name: /etc/pki/elasticfleet-kafka.key - - mode: 640 - - user: 947 - - group: 939 -{% endif %} - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} diff --git a/salt/ssl/remove.sls b/salt/ssl/remove.sls index 28b860205..e91605551 100644 --- a/salt/ssl/remove.sls +++ b/salt/ssl/remove.sls @@ -1,10 +1,7 @@ -trusttheca: - file.absent: - - name: /etc/pki/tls/certs/intca.crt - -symlinkca: - file.absent: - - name: /etc/ssl/certs/intca.crt +# 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. influxdb_key: file.absent: @@ -14,6 +11,14 @@ influxdb_crt: file.absent: - name: /etc/pki/influxdb.crt +telegraf_key: + file.absent: + - name: /etc/pki/telegraf.key + +telegraf_crt: + file.absent: + - name: /etc/pki/telegraf.crt + redis_key: file.absent: - name: /etc/pki/redis.key @@ -30,6 +35,7 @@ etc_filebeat_crt: file.absent: - name: /etc/pki/filebeat.crt +# manager has symlink to /etc/pki/filebeat.crt and /etc/pki/filebeat.p8 filebeatdir: file.absent: - name: /opt/so/saltstack/local/salt/filebeat/files @@ -42,11 +48,13 @@ registry_crt: file.absent: - name: /etc/pki/registry.crt -/etc/pki/elasticsearch.key: - file.absent: [] +elasticsearch_key: + file.absent: + - name: /etc/pki/elasticsearch.key -/etc/pki/elasticsearch.crt: - file.absent: [] +elasticsearch_crt: + file.absent: + - name: /etc/pki/elasticsearch.crt remove_elasticsearch.p12: file.absent: @@ -75,6 +83,7 @@ fbcertdir: kafka_crt: file.absent: - name: /etc/pki/kafka.crt + kafka_key: file.absent: - name: /etc/pki/kafka.key @@ -82,9 +91,67 @@ kafka_key: kafka_logstash_crt: file.absent: - name: /etc/pki/kafka-logstash.crt + kafka_logstash_key: file.absent: - name: /etc/pki/kafka-logstash.key + kafka_logstash_keystore: file.absent: - name: /etc/pki/kafka-logstash.p12 + +elasticfleet_agent_crt: + file.absent: + - name: /etc/pki/elasticfleet-agent.crt + +elasticfleet_agent_key: + file.absent: + - name: /etc/pki/elasticfleet-agent.key + +elasticfleet_agent_p8: + file.absent: + - name: /etc/pki/elasticfleet-agent.p8 + +elasticfleet_kafka_crt: + file.absent: + - name: /etc/pki/elasticfleet-kafka.crt + +elasticfleet_kafka_key: + file.absent: + - name: /etc/pki/elasticfleet-kafka.key + +elasticfleet_logstash_crt: + file.absent: + - name: /etc/pki/elasticfleet-logstash.crt + +elasticfleet_logstash_key: + file.absent: + - name: /etc/pki/elasticfleet-logstash.key + +elasticfleet_logstash_p8: + file.absent: + - name: /etc/pki/elasticfleet-logstash.p8 + +elasticfleet_lumberjack_crt: + file.absent: + - name: /etc/pki/elasticfleet-lumberjack.crt + +elasticfleet_lumberjack_key: + file.absent: + - name: /etc/pki/elasticfleet-lumberjack.key + +elasticfleet_lumberjack_p8: + file.absent: + - name: /etc/pki/elasticfleet-lumberjack.p8 + +elasticfleet_server_crt: + file.absent: + - name: /etc/pki/elasticfleet-server.crt + +elasticfleet_server_key: + file.absent: + - name: /etc/pki/elasticfleet-server.key + +filebeat_p8: + file.absent: + - name: /etc/pki/filebeat.p8 diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index f3f9f446f..aa5b2ed31 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -1,6 +1,6 @@ - - + + @@ -14,6 +14,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22,10 +139,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + Oracle Linux 9 @@ -33,9 +267,9 @@ - + - draft + draft Guide to the Secure Configuration of Oracle Linux 9 This guide presents a catalog of security-relevant configuration settings for Oracle Linux 9. It is a rendering of @@ -78,8 +312,8 @@ trademarks or trademarks of Red Hat, Inc. in the United States and other countries. All other names are registered trademarks or trademarks of their respective companies. anssi - app-srg - app-srg-ctr + app-srg + app-srg-ctr bsi ccn cis @@ -88,344 +322,64 @@ respective companies. cobit5 cui dcid - disa + disa hipaa isa-62443-2009 isa-62443-2013 ism iso27001-2013 - nerc-cip + nerc-cip nist nist-csf - os-srg + os-srg ospp pcidss pcidss4 - stigid - stigref + stigid + stigref - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - + - + - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -448,9 +402,9 @@ respective companies. - + - + @@ -458,9 +412,9 @@ respective companies. - + - + @@ -468,38 +422,24 @@ respective companies. - + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - @@ -520,6 +460,87 @@ respective companies. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -528,14 +549,269 @@ respective companies. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 0.1.76 + 0.1.79 SCAP Security Guide Project SCAP Security Guide Project @@ -549,14 +825,18 @@ respective companies. Gabe Alford <redhatrises@gmail.com> Firas AlShafei <firas.alshafei@us.abb.com> Rodrigo Alvares <ralvares@redhat.com> + am-tux <andrew.miller11@gmail.com> Christopher Anderson <cba@fedoraproject.org> Craig Andrews <candrews@integralblue.com> angystardust <angystardust@users.noreply.github.com> anivan-suse <anastasija.ivanovic@suse.com> anixon-rh <55244503+anixon-rh@users.noreply.github.com> + Anna-Koudelkova <akoudelk@redhat.com> + Arden97 <arden2545@gmail.com> Steve Arnold <sarnold@vctlabs.com> Ikko Ashimine <eltociear@gmail.com> Chuck Atkins <chuck.atkins@kitware.com> + axuan <axuan@redhat.com> Bharath B <bhb@redhat.com> Ryan Ballanger <root@rballang-admin-2.fastenal.com> Alex Baranowski <alex@euro-linux.com> @@ -574,6 +854,7 @@ respective companies. Joseph Bisch <joseph.bisch@gmail.com> Jeff Blank <blank@eclipse.ncsc.mil> Olivier Bonhomme <ptitoliv@ptitoliv.net> + bontreger <bontreger@users.noreply.github.com> Lance Bragstad <lbragstad@gmail.com> Ted Brunell <tbrunell@redhat.com> Marcus Burghardt <maburgha@redhat.com> @@ -585,6 +866,7 @@ respective companies. Carlos <64919342+carlosmmatos@users.noreply.github.com> James Cassell <james.cassell@ll.mit.edu> Frank Caviggia <fcaviggia@users.noreply.github.com> + Sinong Chen <costinchen@tencent.com> Eric Christensen <echriste@redhat.com> Dan Clark <danclark@redhat.com> Jayson Cofell <1051437+70k10@users.noreply.github.com> @@ -600,9 +882,9 @@ respective companies. cueball23 <christoph.alms@westnetz.de> cyarbrough76 <42849651+cyarbrough76@users.noreply.github.com> Maura Dailey <maura@eclipse.ncsc.mil> + Benjamin Deering <ben_deering@jeepingben.net> Klaas Demter <demter@atix.de> denknorr <dennis.knorr@suse.com> - dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dhanushkar-wso2 <dhanushkar@wso2.com> Andrew DiPrinzio <andrew.diprinzio@jhuapl.edu> dom <dominique.blaze@devinci.fr> @@ -614,8 +896,11 @@ respective companies. François Duthilleul <francoisduthilleul@gmail.com> Greg Elin <gregelin@gitmachines.com> eradot4027 <jrtonmac@gmail.com> + ericeberry <ericeberry@gmail.com> ermeratos <manuel.ermer@eviden.net> + Evelyn <evansvevelyn@gmail.com> Alexis Facques <alexis.facques@mythalesgroup.io> + Jan Fader <jan.fader@web.de> Henry Finucane <hfinucane@zscaler.com> Leah Fisher <lfisher047@gmail.com> Marco Fortina <marco_fortina@hotmail.it> @@ -632,11 +917,14 @@ respective companies. Patrik Greco <sikevux@sikevux.se> Steve Grubb <sgrubb@redhat.com> guangyee <gyee@suse.com> + Bhargavi Gudi <bgudi@bgudi-thinkpadt14sgen2i.remote.csb> Christian Hagenest <christian.hagenest@suse.com> Marek Haicman <mhaicman@redhat.com> + Sun, Haoxiang <haoxiang.sun@intel.com> Vern Hart <vern.hart@canonical.com> Alex Haydock <alex@alexhaydock.co.uk> Rebekah Hayes <rhayes@corp.rivierautilities.com> + hazerre <kotadouglas2@gmail.com> Trey Henefield <thenefield@gmail.com> Henning Henkel <henning.henkel@helvetia.ch> hex2a <hex2a@users.noreply.github.com> @@ -675,19 +963,21 @@ respective companies. Amit Kumar <amitkuma@redhat.com> Fen Labalme <fen@civicactions.com> Dexter Le <dexter.le@sap.com> + Dimitri John Ledkov <dimitri.ledkov@surgut.co.uk> Ade Lee <alee@redhat.com> Christopher Lee <Crleekwc@gmail.com> Ian Lee <lee1001@llnl.gov> Jarrett Lee <jarrettl@umd.edu> Joseph Lenox <joseph.lenox@collins.com> + Stefano Libero <stefano.libero@nozominetworks.com> lichtblaugue <guenther.lichtblau@eviden.com> Jan Lieskovsky <jlieskov@redhat.com> Markus Linnala <Markus.Linnala@knowit.fi> Flos Lonicerae <lonicerae@gmail.com> Simon Lukasik <slukasik@redhat.com> + Andrew Lukoshko <andrew.lukoshko@gmail.com> Milan Lysonek <mlysonek@redhat.com> Fredrik Lysén <fredrik@pipemore.se> - Mab879 <207087+Mab879@users.noreply.github.com> Mackemania <8738793+Mackemania@users.noreply.github.com> Caitlin Macleod <caitelatte@gmail.com> Dmitry Makovey <dmakovey@yahoo.com> @@ -763,6 +1053,7 @@ respective companies. Jesse Roland <jesse.roland@onyxpoint.com> Joshua Roys <roysjosh@gmail.com> rrenshaw <bofh69@yahoo.com> + Daniel Ruf <daniel@daniel-ruf.de> Chris Ruffalo <chris.ruffalo@gmail.com> Benjamin Ruland <benjamin.ruland@gmail.com> rumch-se <77793453+rumch-se@users.noreply.github.com> @@ -802,8 +1093,10 @@ respective companies. steven.y.gui <steven_ygui@163.com> Brian Stinson <brian@bstinson.com> Jake Stookey <jakestookey@gmail.com> + Nathan Strahs <135379779+nathanstrahs@users.noreply.github.com> Jonathan Sturges <jsturges@redhat.com> svet-se <svetlin.boychev@suse.com> + Kaushik Talathi <kaushik.talathi1@ibm.com> teacup-on-rockingchair <315160+teacup-on-rockingchair@users.noreply.github.com> Ian Tewksbury <itewk@redhat.com> Philippe Thierry <phil@reseau-libre.net> @@ -823,6 +1116,7 @@ respective companies. VadimDor <29509093+VadimDor@users.noreply.github.com> Trevor Vaughan <tvaughan@onyxpoint.com> vtrubovics <82443408+vtrubovics@users.noreply.github.com> + Sophia Wang <huiwang@redhat.com> Samuel Warren <swarren@redhat.com> wcushen <54533890+wcushen@users.noreply.github.com> Shawn Wells <shawn@redhat.com> @@ -841,6 +1135,9 @@ respective companies. Guang Yee <guang.yee@suse.com> Achilleas John Yfantis <ayfantis@redhat.com> YiLin.Li <YiLin.Li@linux.alibaba.com> + yu410621 <lihuanyu410621@gmail.com> + Xiaojie Yuan <xiyuan@redhat.com> + yungcero <133906218+yungcero@users.noreply.github.com> yunimoo <yunimoo@nekocake.cafe> YuQing <yyq0391@163.com> zhaoyun <zhaoyun@kylinos.cn> @@ -851,11 +1148,11 @@ respective companies. https://github.com/ComplianceAsCode/content/releases/latest - V1R1 + V1R3 DISA STIG for Oracle Linux 9 This profile contains configuration checks that align to the -DISA STIG for Oracle Linux 9 V1R1. - https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux +DISA STIG for Oracle Linux 9 V1R3. + https://www.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux @@ -867,9 +1164,9 @@ DISA STIG for Oracle Linux 9 V1R1. + - @@ -878,10 +1175,11 @@ DISA STIG for Oracle Linux 9 V1R1. + + - @@ -928,6 +1226,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -983,12 +1282,14 @@ DISA STIG for Oracle Linux 9 V1R1. + + @@ -1045,6 +1346,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1122,8 +1424,8 @@ DISA STIG for Oracle Linux 9 V1R1. + - @@ -1138,6 +1440,8 @@ DISA STIG for Oracle Linux 9 V1R1. + + @@ -1188,6 +1492,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1209,11 +1514,11 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1232,6 +1537,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1254,6 +1560,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1281,7 +1588,6 @@ DISA STIG for Oracle Linux 9 V1R1. - @@ -1328,7 +1634,7 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1373,25 +1679,28 @@ DISA STIG for Oracle Linux 9 V1R1. + - - + + + + @@ -1400,10 +1709,11 @@ DISA STIG for Oracle Linux 9 V1R1. + - + @@ -1418,31 +1728,33 @@ DISA STIG for Oracle Linux 9 V1R1. + + - + - V1R1 + V1R3 DISA STIG with GUI for Oracle Linux 9 This profile contains configuration checks that align to the -DISA STIG for Oracle Linux 9 V1R1. +DISA STIG for Oracle Linux 9 V1R3. Warning: The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your overall security posture. If your Information Systems Security Officer (ISSO) lacks a documented operational requirement for a graphical user interface, please consider using the standard DISA STIG for Oracle Linux 9 profile. - https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux + https://www.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux @@ -1454,9 +1766,9 @@ standard DISA STIG for Oracle Linux 9 profile. + - @@ -1465,10 +1777,11 @@ standard DISA STIG for Oracle Linux 9 profile. + + - @@ -1515,6 +1828,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1570,12 +1884,14 @@ standard DISA STIG for Oracle Linux 9 profile. + + @@ -1632,6 +1948,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1709,8 +2026,8 @@ standard DISA STIG for Oracle Linux 9 profile. + - @@ -1725,6 +2042,8 @@ standard DISA STIG for Oracle Linux 9 profile. + + @@ -1775,6 +2094,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1795,11 +2115,11 @@ standard DISA STIG for Oracle Linux 9 profile. - + @@ -1818,6 +2138,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1840,6 +2161,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1867,7 +2189,6 @@ standard DISA STIG for Oracle Linux 9 profile. - @@ -1914,7 +2235,7 @@ standard DISA STIG for Oracle Linux 9 profile. - + @@ -1958,26 +2279,29 @@ standard DISA STIG for Oracle Linux 9 profile. + - - + + + + @@ -1986,10 +2310,11 @@ standard DISA STIG for Oracle Linux 9 profile. + - + @@ -2004,17 +2329,19 @@ standard DISA STIG for Oracle Linux 9 profile. + + - + @@ -2079,6 +2406,96 @@ modification of important files. To list which files on the system differ from w $ rpm -qVa See the man page for rpm to see a complete explanation of each column. + + Verify crypto-policies with RPM + Without cryptographic integrity protections, system executables and files can be altered by +unauthorized users without detection. The RPM package management system can check the hashes +of installed software packages, including many that are important to system security. + +If the file was not expected to change, investigate the cause of the change using audit logs +or other means. The package can then be reinstalled to restore the file. Run the following +command to determine which package owns the file: +$ rpm -qf FILENAME + + +The package can be reinstalled from a yum repository using the command: +$ sudo yum reinstall crypto-policies + + SRG-OS-000478-GPOS-00223 + SRG-OS-000396-GPOS-00176 + OL09-00-000244 + SV-271481r1117272_rule + The crypto-policies package defines the cryptography policies for the system. +If the files are changed from those shipped with the operating system, +It may be possible for Oracle Linux 9 to use cryptographic functions that are not FIPS 140-3 approved. + # Remediation is applicable only in certain platforms +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ); then + +files_with_incorrect_hash="$(rpm -V crypto-policies)" + +if [ -n "$files_with_incorrect_hash" ]; then + yum reinstall -y crypto-policies +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000244 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_crypto_policies + +- name: Verify crypto-policies with RPM - Read files with incorrect hash + ansible.builtin.command: rpm -V crypto-policies + register: files_with_incorrect_hash + changed_when: false + failed_when: files_with_incorrect_hash.rc > 1 + check_mode: false + when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) + tags: + - DISA-STIG-OL09-00-000244 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_crypto_policies + +- name: Verify crypto-policies with RPM - Reinstall packages of files with incorrect + hash + ansible.builtin.command: yum reinstall -y crypto-policies + when: + - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) + - files_with_incorrect_hash.stdout_lines is defined + - (files_with_incorrect_hash.stdout_lines | length > 0) + tags: + - DISA-STIG-OL09-00-000244 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_crypto_policies + + + + + + + + Verify File Hashes with RPM Without cryptographic integrity protections, system executables and files can be altered by @@ -2123,8 +2540,6 @@ can be affected. DSS06.02 3.3.8 3.4.1 - CCI-000366 - CCI-001749 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -2158,15 +2573,16 @@ can be affected. PR.DS-8 PR.IP-1 Req-11.5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1409 11.5.2 - OL09-00-000243 - SV-271480r1091152_rule + OL09-00-000243 + SV-271480r1091152_rule The hashes of important files like system executables should match the information given by the RPM database. Executables with erroneous hashes could be a sign of nefarious activity on the system. # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ); then # Find which files have incorrect hash (not in /etc, because of the system related config files) and then get files names files_with_incorrect_hash="$(rpm -Va --noconfig | grep -E '^..5' | awk '{print $NF}' )" @@ -2208,13 +2624,14 @@ fi - rpm_verify_hashes - name: 'Set fact: Package manager reinstall command' - set_fact: + ansible.builtin.set_fact: package_manager_reinstall_cmd: yum reinstall -y when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) - - ansible_distribution in [ "Fedora", "RedHat", "CentOS", "OracleLinux" ] + and "ostree" in ansible_proc_cmdline ) + - ansible_distribution in [ "Fedora", "RedHat", "CentOS", "OracleLinux", "AlmaLinux" + ] tags: - CJIS-5.10.4.1 - DISA-STIG-OL09-00-000243 @@ -2236,12 +2653,12 @@ fi - rpm_verify_hashes - name: 'Set fact: Package manager reinstall command (zypper)' - set_fact: + ansible.builtin.set_fact: package_manager_reinstall_cmd: zypper in -f -y when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - ansible_distribution == "SLES" tags: - CJIS-5.10.4.1 @@ -2264,8 +2681,8 @@ fi - rpm_verify_hashes - name: Read files with incorrect hash - command: rpm -Va --nodeps --nosize --nomtime --nordev --nocaps --nolinkto --nouser - --nogroup --nomode --noghost --noconfig + ansible.builtin.command: rpm -Va --nodeps --nosize --nomtime --nordev --nocaps --nolinkto + --nouser --nogroup --nomode --noghost --noconfig register: files_with_incorrect_hash changed_when: false failed_when: files_with_incorrect_hash.rc > 1 @@ -2273,7 +2690,7 @@ fi when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - (package_manager_reinstall_cmd is defined) tags: - CJIS-5.10.4.1 @@ -2296,7 +2713,7 @@ fi - rpm_verify_hashes - name: Create list of packages - command: rpm -qf "{{ item }}" + ansible.builtin.command: rpm -qf "{{ item }}" with_items: '{{ files_with_incorrect_hash.stdout_lines | map(''regex_findall'', ''^[.]+[5]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'') | list | unique }}' @@ -2306,7 +2723,7 @@ fi when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - files_with_incorrect_hash.stdout_lines is defined - (files_with_incorrect_hash.stdout_lines | length > 0) tags: @@ -2330,13 +2747,13 @@ fi - rpm_verify_hashes - name: Reinstall packages of files with incorrect hash - command: '{{ package_manager_reinstall_cmd }} ''{{ item }}''' + ansible.builtin.command: '{{ package_manager_reinstall_cmd }} ''{{ item }}''' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - files_with_incorrect_hash.stdout_lines is defined - (package_manager_reinstall_cmd is defined and (files_with_incorrect_hash.stdout_lines | length > 0)) @@ -2413,8 +2830,6 @@ can be affected. MEA02.01 3.3.8 3.4.1 - CCI-001494 - CCI-001496 4.3.3.3.9 4.3.3.5.8 4.3.3.7.3 @@ -2466,11 +2881,11 @@ can be affected. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4.2 - CIP-003-8 R6 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 + CIP-003-8 R4.2 + CIP-003-8 R6 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 CM-6(d) CM-6(c) SI-7 @@ -2482,15 +2897,16 @@ can be affected. PR.IP-1 PR.PT-1 Req-11.5 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000278-GPOS-00108 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000278-GPOS-00108 + 1409 11.5.2 Ownership of binaries and configuration files that is incorrect could allow an unauthorized user to gain privileges that they should not have. The ownership set by the vendor should be maintained. Any deviations from this baseline should be investigated. # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ); then # Declare array to hold set of RPM packages we need to correct permissions for declare -A SETPERMS_RPM_DICT @@ -2540,15 +2956,15 @@ fi - rpm_verify_ownership - name: Read list of files with incorrect ownership - command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev - --nocaps --nolinkto --nomode + ansible.builtin.command: rpm -Va --nodeps --nosignature --nofiledigest --nosize + --nomtime --nordev --nocaps --nolinkto --nomode register: files_with_incorrect_ownership failed_when: files_with_incorrect_ownership.rc > 1 changed_when: false check_mode: false when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2569,7 +2985,7 @@ fi - rpm_verify_ownership - name: Create list of packages - command: rpm -qf "{{ item }}" + ansible.builtin.command: rpm -qf "{{ item }}" with_items: '{{ files_with_incorrect_ownership.stdout_lines | map(''regex_findall'', ''^[.]+[U|G]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'') | list | unique }}' @@ -2579,7 +2995,7 @@ fi when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - (files_with_incorrect_ownership.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2601,13 +3017,13 @@ fi - rpm_verify_ownership - name: Correct file ownership with RPM - command: rpm --restore '{{ item }}' + ansible.builtin.command: rpm --restore '{{ item }}' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - (files_with_incorrect_ownership.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2686,10 +3102,6 @@ can be affected. MEA02.01 3.3.8 3.4.1 - CCI-001493 - CCI-001494 - CCI-001495 - CCI-001496 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -2746,11 +3158,11 @@ can be affected. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4.2 - CIP-003-8 R6 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 + CIP-003-8 R4.2 + CIP-003-8 R6 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 CM-6(d) CM-6(c) SI-7 @@ -2763,16 +3175,17 @@ can be affected. PR.IP-1 PR.PT-1 Req-11.5 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - SRG-OS-000278-GPOS-00108 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + SRG-OS-000278-GPOS-00108 + 1409 11.5.2 Permissions on system binaries and configuration files that are too generous could allow an unauthorized user to gain privileges that they should not have. The permissions set by the vendor should be maintained. Any deviations from this baseline should be investigated. # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ); then # Declare array to hold set of RPM packages we need to correct permissions for declare -A SETPERMS_RPM_DICT @@ -2827,15 +3240,15 @@ fi - rpm_verify_permissions - name: Read list of files with incorrect permissions - command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev - --nocaps --nolinkto --nouser --nogroup + ansible.builtin.command: rpm -Va --nodeps --nosignature --nofiledigest --nosize + --nomtime --nordev --nocaps --nolinkto --nouser --nogroup register: files_with_incorrect_permissions failed_when: files_with_incorrect_permissions.rc > 1 changed_when: false check_mode: false when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2857,7 +3270,7 @@ fi - rpm_verify_permissions - name: Create list of packages - command: rpm -qf "{{ item }}" + ansible.builtin.command: rpm -qf "{{ item }}" with_items: '{{ files_with_incorrect_permissions.stdout_lines | map(''regex_findall'', ''^[.]+[M]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'') | list | unique }}' @@ -2867,7 +3280,7 @@ fi when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - (files_with_incorrect_permissions.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2890,13 +3303,13 @@ fi - rpm_verify_permissions - name: Correct file permissions with RPM - command: rpm --restore '{{ item }}' + ansible.builtin.command: rpm --restore '{{ item }}' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) - (files_with_incorrect_permissions.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2973,8 +3386,6 @@ $ sudo yum install aide DSS05.07 DSS06.02 DSS06.06 - CCI-002696 - CCI-001744 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -2985,10 +3396,6 @@ $ sudo yum install aide SR 4.1 SR 6.2 SR 7.6 - 1034 - 1288 - 1341 - 1417 A.11.2.4 A.12.1.2 A.12.2.1 @@ -3012,12 +3419,16 @@ $ sudo yum install aide PR.IP-1 PR.IP-3 Req-11.5 - SRG-OS-000445-GPOS-00199 + SRG-OS-000445-GPOS-00199 R76 R79 + 1034 + 1288 + 1341 + 1417 11.5.2 - OL09-00-000300 - SV-271496r1091200_rule + OL09-00-000300 + SV-271496r1091200_rule The AIDE package must be installed if it is to be available for integrity checking. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -3047,7 +3458,7 @@ fi - package_aide_installed - name: Ensure aide is installed - package: + ansible.builtin.package: name: aide state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -3107,6 +3518,14 @@ The newly-generated database can be installed as follows: To initiate a manual check, run the following command: $ sudo /usr/sbin/aide --check If this check produces any unexpected output, investigate. + In RHEL Image Mode (bootc) systems, the AIDE database must be regenerated after each system update. +Image Mode systems receive updates through new container images that may include modified files. +After applying system updates, run the following commands to regenerate the AIDE database: +$ sudo /usr/sbin/aide --init +Then replace the existing database: +$ sudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz +Failure to regenerate the AIDE database after updates will result in false positive alerts +for legitimate system changes introduced by the update process. 1 11 12 @@ -3139,8 +3558,6 @@ If this check produces any unexpected output, investigate.DSS05.07 DSS06.02 DSS06.06 - CCI-002696 - CCI-001744 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -3174,7 +3591,7 @@ If this check produces any unexpected output, investigate.PR.IP-1 PR.IP-3 Req-11.5 - SRG-OS-000445-GPOS-00199 + SRG-OS-000445-GPOS-00199 R76 R79 11.5.2 @@ -3228,9 +3645,10 @@ fi - no_reboot_needed - restrict_strategy -- name: Build and Test AIDE Database - Build and Test AIDE Database - ansible.builtin.command: /usr/sbin/aide --init - changed_when: true +- name: Build and Test AIDE Database - Check Whether the Stock AIDE Database Exists + ansible.builtin.stat: + path: /var/lib/aide/aide.db.new.gz + register: aide_database_stat when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 @@ -3244,11 +3662,13 @@ fi - no_reboot_needed - restrict_strategy -- name: Build and Test AIDE Database - Check Whether the Stock AIDE Database Exists - ansible.builtin.stat: - path: /var/lib/aide/aide.db.new.gz - register: aide_database_stat - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) +- name: Build and Test AIDE Database - Build and Test AIDE Database + ansible.builtin.command: /usr/sbin/aide --init + changed_when: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists) + register: aide_database_init tags: - CJIS-5.10.1.3 - NIST-800-53-CM-6(a) @@ -3269,7 +3689,8 @@ fi remote_src: true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists) + - aide_database_init is changed + - not ansible_check_mode tags: - CJIS-5.10.1.3 - NIST-800-53-CM-6(a) @@ -3292,15 +3713,11 @@ fi Configure AIDE to Verify the Audit Tools The operating system file integrity tool must be configured to protect the integrity of the audit tools. - CCI-001496 - CCI-001494 - CCI-001495 - CCI-001493 AU-9(3) AU-9(3).1 - SRG-OS-000278-GPOS-00108 - OL09-00-000710 - SV-271569r1091419_rule + SRG-OS-000278-GPOS-00108 + OL09-00-000710 + SV-271569r1091419_rule Protecting the integrity of the tools used for auditing purposes is a critical step toward ensuring the integrity of audit information. Audit information includes all information (e.g., audit records, audit settings, @@ -3336,44 +3753,44 @@ fi -if grep -i '^.*/usr/sbin/auditctl.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/auditctl.*#/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/auditctl.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/auditctl.*#/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/auditd.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/auditd.*#/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/auditd.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/auditd.*#/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/ausearch.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/ausearch.*#/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/ausearch.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/ausearch.*#/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/aureport.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/aureport.*#/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/aureport.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/aureport.*#/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/autrace.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/autrace.*#/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/autrace.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/autrace.*#/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/augenrules.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/augenrules.*#/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/augenrules.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/augenrules.*#/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/rsyslogd.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/rsyslogd.*#/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/rsyslogd.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/rsyslogd.*#/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi @@ -3413,7 +3830,7 @@ fi when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - name: Ensure aide is installed - package: + ansible.builtin.package: name: '{{ item }}' state: present with_items: @@ -3430,8 +3847,23 @@ fi - no_reboot_needed - restrict_strategy +- name: Configure AIDE to Verify the Audit Tools - Gather the package facts + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000710 + - NIST-800-53-AU-9(3) + - NIST-800-53-AU-9(3).1 + - aide_check_audit_tools + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Set audit_tools fact - set_fact: + ansible.builtin.set_fact: audit_tools: - /usr/sbin/auditctl - /usr/sbin/auditd @@ -3453,12 +3885,15 @@ fi - restrict_strategy - name: Ensure existing AIDE configuration for audit tools are correct - lineinfile: + ansible.builtin.lineinfile: path: /etc/aide.conf regexp: ^{{ item }}\s line: '{{ item }} p+i+n+u+g+s+b+acl+xattrs+sha512' + create: true with_items: '{{ audit_tools }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) @@ -3471,11 +3906,14 @@ fi - restrict_strategy - name: Configure AIDE to properly protect audit tools - lineinfile: + ansible.builtin.lineinfile: path: /etc/aide.conf line: '{{ item }} p+i+n+u+g+s+b+acl+xattrs+sha512' + create: true with_items: '{{ audit_tools }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) @@ -3536,9 +3974,6 @@ The usage of cron's special time codes, such as @daily a DSS05.07 DSS06.02 DSS06.06 - CCI-002702 - CCI-001744 - CCI-002699 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -3574,13 +4009,13 @@ The usage of cron's special time codes, such as @daily a PR.IP-1 PR.IP-3 Req-11.5 - SRG-OS-000363-GPOS-00150 - SRG-OS-000446-GPOS-00200 - SRG-OS-000447-GPOS-00201 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 R76 11.5.2 - OL09-00-000301 - SV-271497r1092471_rule + OL09-00-000301 + SV-271497r1092471_rule By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files. @@ -3603,11 +4038,21 @@ if ! rpm -q --quiet "aide" ; then yum install -y "aide" fi -if ! grep -q "/usr/sbin/aide --check" /etc/crontab ; then - echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab + +if ! rpm -q --quiet "cronie" ; then + yum install -y "cronie" +fi + + + +CRON_FILE="/etc/crontab" + + +if ! grep -q "/usr/sbin/aide --check" "${CRON_FILE}" ; then + echo "05 4 * * * root /usr/sbin/aide --check" >> "${CRON_FILE}" else - sed -i '\!^.* --check.*$!d' /etc/crontab - echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab + sed -i '\!^.* --check.*$!d' "${CRON_FILE}" + echo "05 4 * * * root /usr/sbin/aide --check" >> "${CRON_FILE}" fi else @@ -3633,11 +4078,9 @@ fi - restrict_strategy - name: Ensure AIDE is installed - package: - name: '{{ item }}' + ansible.builtin.package: + name: aide state: present - with_items: - - aide when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 @@ -3654,51 +4097,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Set cron package name - RedHat - set_fact: - cron_pkg_name: cronie - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_os_family == "RedHat" or ansible_os_family == "Suse" - tags: - - CJIS-5.10.1.3 - - DISA-STIG-OL09-00-000301 - - NIST-800-53-CM-6(a) - - NIST-800-53-SI-7 - - NIST-800-53-SI-7(1) - - PCI-DSS-Req-11.5 - - PCI-DSSv4-11.5.2 - - aide_periodic_cron_checking - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Set cron package name - Debian - set_fact: - cron_pkg_name: cron - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_os_family == "Debian" - tags: - - CJIS-5.10.1.3 - - DISA-STIG-OL09-00-000301 - - NIST-800-53-CM-6(a) - - NIST-800-53-SI-7 - - NIST-800-53-SI-7(1) - - PCI-DSS-Req-11.5 - - PCI-DSSv4-11.5.2 - - aide_periodic_cron_checking - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - name: Install cron - package: - name: '{{ cron_pkg_name }}' + ansible.builtin.package: + name: cronie state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: @@ -3716,15 +4117,36 @@ fi - no_reboot_needed - restrict_strategy +- name: Gather list of installed packages + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - PCI-DSS-Req-11.5 + - PCI-DSSv4-11.5.2 + - aide_periodic_cron_checking + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Configure Periodic Execution of AIDE - cron: + ansible.builtin.cron: name: run AIDE check minute: 5 hour: 4 - weekday: 0 user: root job: /usr/sbin/aide --check - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + register: crontab_check + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '''cronie'' in ansible_facts.packages' tags: - CJIS-5.10.1.3 - DISA-STIG-OL09-00-000301 @@ -3779,9 +4201,6 @@ AIDE can be executed periodically through other means; this is merely one exampl DSS05.02 DSS05.05 DSS05.07 - CCI-002702 - CCI-001744 - CCI-002699 4.3.4.3.2 4.3.4.3.3 SR 6.2 @@ -3801,12 +4220,12 @@ AIDE can be executed periodically through other means; this is merely one exampl DE.CM-7 PR.IP-1 PR.IP-3 - SRG-OS-000363-GPOS-00150 - SRG-OS-000446-GPOS-00200 - SRG-OS-000447-GPOS-00201 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 R76 - OL09-00-000301 - SV-271497r1092471_rule + OL09-00-000301 + SV-271497r1092471_rule Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may @@ -3868,7 +4287,7 @@ fi - always - name: Ensure AIDE is installed - package: + ansible.builtin.package: name: '{{ item }}' state: present with_items: @@ -3886,7 +4305,7 @@ fi - restrict_strategy - name: Configure Notification of Post-AIDE Scan Details - cron: + ansible.builtin.cron: name: run AIDE check minute: 5 hour: 4 @@ -3945,7 +4364,6 @@ submits to this process. BAI06.01 DSS06.02 3.13.11 - CCI-000366 4.3.4.4.4 SR 3.1 SR 3.3 @@ -3962,9 +4380,9 @@ submits to this process. CM-6(a) PR.DS-6 PR.DS-8 - SRG-OS-000480-GPOS-00227 - OL09-00-000302 - SV-271498r1091206_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000302 + SV-271498r1091206_rule File integrity tools use cryptographic hashes for verifying file contents and directories have not been altered. These hashes must be FIPS 140-2 approved cryptographic hashes. # Remediation is applicable only in certain platforms @@ -4065,14 +4483,34 @@ fi - medium_severity - no_reboot_needed +- name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Gather the package + facts + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Remove forbidden hashes ansible.builtin.replace: path: '{{ aide_conf }}' regexp: (^\s*[A-Z][A-Za-z_]*\s*=.*?)({{ item }}\+|\+?{{ item }})(.*) replace: \1\3 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' loop: '{{ forbidden_hashes }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000302 - NIST-800-171-3.13.11 @@ -4091,7 +4529,9 @@ fi path: '{{ aide_conf }}' regexp: (^\s*[A-Z][A-Za-z_]*\s*=)((?:(?!\+?sha512).)*)\s*$ replace: \1\2+sha512 - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000302 - NIST-800-171-3.13.11 @@ -4132,7 +4572,6 @@ The remediation provided with this rule adds acl to all r BAI03.05 BAI06.01 DSS06.02 - CCI-000366 4.3.4.4.4 SR 3.1 SR 3.3 @@ -4149,10 +4588,10 @@ The remediation provided with this rule adds acl to all r CM-6(a) PR.DS-6 PR.DS-8 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R76 - OL09-00-000303 - SV-271499r1091209_rule + OL09-00-000303 + SV-271499r1091209_rule ACLs can provide permissions beyond those permitted through the file mode and must be verified by the file integrity tools. # Remediation is applicable only in certain platforms @@ -4188,7 +4627,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather list of packages + - name: Gather the package facts package_facts: manager: auto tags: @@ -4203,14 +4642,32 @@ fi - no_reboot_needed - restrict_strategy +- name: Gather list of packages + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000303 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_verify_acls + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - name: Get rules groups - shell: | + ansible.builtin.shell: | set -o pipefail LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '''aide'' in ansible_facts.packages' register: find_rules_groups_results + changed_when: false + check_mode: false tags: - DISA-STIG-OL09-00-000303 - NIST-800-53-CM-6(a) @@ -4224,7 +4681,7 @@ fi - restrict_strategy - name: Ensure the acl rule is present when aide is installed. - replace: + ansible.builtin.replace: path: /etc/aide.conf regexp: (^\s*{{ item }}\s*=\s*)(?!.*acl)([^\s]*) replace: \g<1>\g<2>+acl @@ -4271,7 +4728,6 @@ The remediation provided with this rule adds xattrs to al BAI03.05 BAI06.01 DSS06.02 - CCI-000366 4.3.4.4.4 SR 3.1 SR 3.3 @@ -4288,10 +4744,10 @@ The remediation provided with this rule adds xattrs to al CM-6(a) PR.DS-6 PR.DS-8 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R76 - OL09-00-000304 - SV-271500r1091212_rule + OL09-00-000304 + SV-271500r1091212_rule Extended attributes in file systems are used to contain arbitrary data and file metadata with security implications. # Remediation is applicable only in certain platforms @@ -4327,7 +4783,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather list of packages + - name: Gather the package facts package_facts: manager: auto tags: @@ -4342,14 +4798,32 @@ fi - no_reboot_needed - restrict_strategy +- name: Gather list of packages + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000304 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_verify_ext_attributes + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - name: Get rules groups - shell: | + ansible.builtin.shell: | set -o pipefail LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '''aide'' in ansible_facts.packages' register: find_rules_groups_results + changed_when: false + check_mode: false tags: - DISA-STIG-OL09-00-000304 - NIST-800-53-CM-6(a) @@ -4363,7 +4837,7 @@ fi - restrict_strategy - name: Ensure the xattrs rule is present when aide is installed. - replace: + ansible.builtin.replace: path: /etc/aide.conf regexp: (^\s*{{ item }}\s*=\s*)(?!.*xattrs)([^\s]*) replace: \g<1>\g<2>+xattrs @@ -4397,25 +4871,48 @@ fi Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. Audit tools must have the correct group owner. - CCI-001493 AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - OL09-00-002570 - SV-271824r1092184_rule + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002570 + SV-271824r1092184_rule Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /sbin/auditctl -chgrp 0 /sbin/aureport -chgrp 0 /sbin/ausearch -chgrp 0 /sbin/autrace -chgrp 0 /sbin/auditd -chgrp 0 /sbin/rsyslogd -chgrp 0 /sbin/augenrules +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/sbin/auditctl" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/auditctl +fi +if ! stat -c "%g %G" "/sbin/aureport" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/aureport +fi +if ! stat -c "%g %G" "/sbin/ausearch" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/ausearch +fi +if ! stat -c "%g %G" "/sbin/autrace" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/autrace +fi +if ! stat -c "%g %G" "/sbin/auditd" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/auditd +fi +if ! stat -c "%g %G" "/sbin/rsyslogd" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/rsyslogd +fi +if ! stat -c "%g %G" "/sbin/augenrules" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/augenrules +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -4434,8 +4931,23 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_audit_tools_group_ownership_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_audit_tools_group_ownership_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002570 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /sbin/auditctl - stat: + ansible.builtin.stat: path: /sbin/auditctl register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4449,10 +4961,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/auditctl - file: +- name: Ensure group owner on /sbin/auditctl + ansible.builtin.file: path: /sbin/auditctl - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4467,7 +4980,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/aureport - stat: + ansible.builtin.stat: path: /sbin/aureport register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4481,10 +4994,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/aureport - file: +- name: Ensure group owner on /sbin/aureport + ansible.builtin.file: path: /sbin/aureport - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4499,7 +5013,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/ausearch - stat: + ansible.builtin.stat: path: /sbin/ausearch register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4513,10 +5027,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/ausearch - file: +- name: Ensure group owner on /sbin/ausearch + ansible.builtin.file: path: /sbin/ausearch - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4531,7 +5046,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/autrace - stat: + ansible.builtin.stat: path: /sbin/autrace register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4545,10 +5060,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/autrace - file: +- name: Ensure group owner on /sbin/autrace + ansible.builtin.file: path: /sbin/autrace - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4563,7 +5079,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditd - stat: + ansible.builtin.stat: path: /sbin/auditd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4577,10 +5093,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/auditd - file: +- name: Ensure group owner on /sbin/auditd + ansible.builtin.file: path: /sbin/auditd - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4595,7 +5112,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/rsyslogd - stat: + ansible.builtin.stat: path: /sbin/rsyslogd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4609,10 +5126,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/rsyslogd - file: +- name: Ensure group owner on /sbin/rsyslogd + ansible.builtin.file: path: /sbin/rsyslogd - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4627,7 +5145,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/augenrules - stat: + ansible.builtin.stat: path: /sbin/augenrules register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4641,10 +5159,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/augenrules - file: +- name: Ensure group owner on /sbin/augenrules + ansible.builtin.file: path: /sbin/augenrules - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4672,25 +5191,48 @@ fi Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. Audit tools must have the correct owner. - CCI-001493 AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - OL09-00-002571 - SV-271825r1092187_rule + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002571 + SV-271825r1092187_rule Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /sbin/auditctl -chown 0 /sbin/aureport -chown 0 /sbin/ausearch -chown 0 /sbin/autrace -chown 0 /sbin/auditd -chown 0 /sbin/rsyslogd -chown 0 /sbin/augenrules +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/sbin/auditctl" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/auditctl +fi +if ! stat -c "%u %U" "/sbin/aureport" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/aureport +fi +if ! stat -c "%u %U" "/sbin/ausearch" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/ausearch +fi +if ! stat -c "%u %U" "/sbin/autrace" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/autrace +fi +if ! stat -c "%u %U" "/sbin/auditd" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/auditd +fi +if ! stat -c "%u %U" "/sbin/rsyslogd" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/rsyslogd +fi +if ! stat -c "%u %U" "/sbin/augenrules" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/augenrules +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -4709,8 +5251,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_audit_tools_ownership_newown variable if represented by uid + ansible.builtin.set_fact: + file_audit_tools_ownership_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002571 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /sbin/auditctl - stat: + ansible.builtin.stat: path: /sbin/auditctl register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4724,10 +5280,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/auditctl - file: +- name: Ensure owner on /sbin/auditctl + ansible.builtin.file: path: /sbin/auditctl - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4742,7 +5299,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/aureport - stat: + ansible.builtin.stat: path: /sbin/aureport register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4756,10 +5313,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/aureport - file: +- name: Ensure owner on /sbin/aureport + ansible.builtin.file: path: /sbin/aureport - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4774,7 +5332,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/ausearch - stat: + ansible.builtin.stat: path: /sbin/ausearch register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4788,10 +5346,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/ausearch - file: +- name: Ensure owner on /sbin/ausearch + ansible.builtin.file: path: /sbin/ausearch - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4806,7 +5365,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/autrace - stat: + ansible.builtin.stat: path: /sbin/autrace register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4820,10 +5379,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/autrace - file: +- name: Ensure owner on /sbin/autrace + ansible.builtin.file: path: /sbin/autrace - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4838,7 +5398,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditd - stat: + ansible.builtin.stat: path: /sbin/auditd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4852,10 +5412,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/auditd - file: +- name: Ensure owner on /sbin/auditd + ansible.builtin.file: path: /sbin/auditd - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4870,7 +5431,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/rsyslogd - stat: + ansible.builtin.stat: path: /sbin/rsyslogd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4884,10 +5445,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/rsyslogd - file: +- name: Ensure owner on /sbin/rsyslogd + ansible.builtin.file: path: /sbin/rsyslogd - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4902,7 +5464,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/augenrules - stat: + ansible.builtin.stat: path: /sbin/augenrules register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4916,10 +5478,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/augenrules - file: +- name: Ensure owner on /sbin/augenrules + ansible.builtin.file: path: /sbin/augenrules - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4947,13 +5510,12 @@ fi Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. Audit tools must have a mode of 0755 or less permissive. - CCI-001493 AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - OL09-00-002572 - SV-271826r1092190_rule + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002572 + SV-271826r1092190_rule Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. # Remediation is applicable only in certain platforms @@ -4991,7 +5553,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditctl - stat: + ansible.builtin.stat: path: /sbin/auditctl register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5006,7 +5568,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/auditctl - file: + ansible.builtin.file: path: /sbin/auditctl mode: u-s,g-ws,o-wt when: @@ -5023,7 +5585,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/aureport - stat: + ansible.builtin.stat: path: /sbin/aureport register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5038,7 +5600,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/aureport - file: + ansible.builtin.file: path: /sbin/aureport mode: u-s,g-ws,o-wt when: @@ -5055,7 +5617,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/ausearch - stat: + ansible.builtin.stat: path: /sbin/ausearch register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5070,7 +5632,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/ausearch - file: + ansible.builtin.file: path: /sbin/ausearch mode: u-s,g-ws,o-wt when: @@ -5087,7 +5649,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/autrace - stat: + ansible.builtin.stat: path: /sbin/autrace register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5102,7 +5664,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/autrace - file: + ansible.builtin.file: path: /sbin/autrace mode: u-s,g-ws,o-wt when: @@ -5119,7 +5681,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditd - stat: + ansible.builtin.stat: path: /sbin/auditd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5134,7 +5696,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/auditd - file: + ansible.builtin.file: path: /sbin/auditd mode: u-s,g-ws,o-wt when: @@ -5151,7 +5713,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/rsyslogd - stat: + ansible.builtin.stat: path: /sbin/rsyslogd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5166,7 +5728,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/rsyslogd - file: + ansible.builtin.file: path: /sbin/rsyslogd mode: u-s,g-ws,o-wt when: @@ -5183,7 +5745,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/augenrules - stat: + ansible.builtin.stat: path: /sbin/augenrules register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5198,7 +5760,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/augenrules - file: + ansible.builtin.file: path: /sbin/augenrules mode: u-s,g-ws,o-wt when: @@ -5238,7 +5800,6 @@ Security Levels 1, 2, 3, or 4 for use on Oracle Linux 9. See http://csrc.nist.gov/publications/PubsFIPS.html for more information. - Enable Dracut FIPS Module @@ -5263,13 +5824,8 @@ undergone this certification. This means providing documentation, test results, information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-002450 - CCI-000068 - CCI-002418 - CCI-000877 - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-12(2) SC-12(3) IA-7 @@ -5277,16 +5833,17 @@ this process. CM-6(a) SC-12 FCS_RBG_EXT.1 - SRG-OS-000478-GPOS-00223 - OL09-00-000070 - SV-271454r1092458_rule + SRG-OS-000478-GPOS-00223 + 1446 + OL09-00-000070 + SV-271454r1092458_rule Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. - + # Remediation is applicable only in certain platforms -if ( ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then fips-mode-setup --enable FIPS_CONF="/etc/dracut.conf.d/40-fips.conf" @@ -5317,15 +5874,14 @@ fi - restrict_strategy - name: Check to see the current status of FIPS mode - command: /usr/bin/fips-mode-setup --check + ansible.builtin.command: /usr/bin/fips-mode-setup --check register: is_fips_enabled changed_when: false failed_when: false - when: - - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) and not ( lookup("env", "container") == + "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-000070 @@ -5343,12 +5899,12 @@ fi - restrict_strategy - name: Enable FIPS mode - command: /usr/bin/fips-mode-setup --enable + ansible.builtin.command: /usr/bin/fips-mode-setup --enable when: - - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) and not ( lookup("env", "container") == + "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - is_fips_enabled.stdout.find('FIPS mode is enabled.') == -1 tags: @@ -5367,14 +5923,13 @@ fi - restrict_strategy - name: Enable Dracut FIPS Module - lineinfile: + ansible.builtin.lineinfile: path: /etc/dracut.conf.d/40-fips.conf line: add_dracutmodules+=" fips " - when: - - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) and not ( lookup("env", "container") == + "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-000070 @@ -5418,13 +5973,8 @@ Enabling FIPS mode on a preexisting system involves a number of modifications to You can find the list of FIPS certified modules at https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search. This rule checks if the system is running in FIPS mode. - CCI-002450 - CCI-000068 - CCI-002418 - CCI-000877 - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 CM-3(6) SC-12(2) SC-12(3) @@ -5440,18 +5990,20 @@ This rule checks if the system is running in FIPS mode. FCS_CKM.2 FCS_TLSC_EXT.1 FCS_RBG_EXT.1 - SRG-OS-000478-GPOS-00223 - SRG-OS-000396-GPOS-00176 - OL09-00-000070 - SV-271454r1092458_rule + SRG-OS-000478-GPOS-00223 + SRG-OS-000396-GPOS-00176 + 1446 + OL09-00-000070 + SV-271454r1092458_rule Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. + # Remediation is applicable only in certain platforms if ( ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then cat > /usr/lib/bootc/kargs.d/01-fips.toml << EOF kargs = ["fips=1"] EOF @@ -5498,11 +6050,8 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000068 - CCI-000803 - CCI-002450 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-12(2) SC-12(3) IA-7 @@ -5513,6 +6062,7 @@ submits to this process. protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. + @@ -5520,6 +6070,45 @@ and validated. + + System Wide Crypto Policy Files Must Point to FIPS Policy + All files in /etc/crypto-policies/back-ends/ except for nss.config should be symlinks pointing +to /usr/share/crypto-policies/FIPS/ + +$ stat -c%N /etc/crypto-policies/back-ends/* +'/etc/crypto-policies/back-ends/bind.config' -> '/usr/share/crypto-policies/FIPS/bind.txt' +'/etc/crypto-policies/back-ends/gnutls.config' -> '/usr/share/crypto-policies/FIPS/gnutls.txt' +'/etc/crypto-policies/back-ends/java.config' -> '/usr/share/crypto-policies/FIPS/java.txt' +'/etc/crypto-policies/back-ends/javasystem.config' -> '/usr/share/crypto-policies/FIPS/javasystem.txt' +'/etc/crypto-policies/back-ends/krb5.config' -> '/usr/share/crypto-policies/FIPS/krb5.txt' +'/etc/crypto-policies/back-ends/libreswan.config' -> '/usr/share/crypto-policies/FIPS/libreswan.txt' +'/etc/crypto-policies/back-ends/libssh.config' -> '/usr/share/crypto-policies/FIPS/libssh.txt' +'/etc/crypto-policies/back-ends/nss.config' +'/etc/crypto-policies/back-ends/openssh.config' -> '/usr/share/crypto-policies/FIPS/openssh.txt' +'/etc/crypto-policies/back-ends/opensshserver.config' -> '/usr/share/crypto-policies/FIPS/opensshserver.txt' +'/etc/crypto-policies/back-ends/opensslcnf.config' -> '/usr/share/crypto-policies/FIPS/opensslcnf.txt' +'/etc/crypto-policies/back-ends/openssl.config' -> '/usr/share/crypto-policies/FIPS/openssl.txt' +'/etc/crypto-policies/back-ends/openssl_fips.config' -> '/usr/share/crypto-policies/FIPS/openssl_fips.txt' + + + SC-13 + MA-4(6) + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + OL09-00-000242 + SV-271479r1092621_rule + Centralized cryptographic policies simplify applying secure ciphers across an operating +system and the applications that run on that operating system. Use of weak or untested +encryption algorithms undermines the purposes of using encryption to protect data. + + + + + + + + Set kernel parameter 'crypto.fips_enabled' to 1 System running in FIPS mode is indicated by kernel parameter @@ -5547,32 +6136,29 @@ undergone this certification. This means providing documentation, test results, information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-002450 - CCI-000068 - CCI-002418 - CCI-000877 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-12(2) SC-12(3) IA-7 SC-13 CM-6(a) SC-12 - SRG-OS-000033-GPOS-00014 - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - SRG-OS-000396-GPOS-00176 - SRG-OS-000423-GPOS-00187 - SRG-OS-000478-GPOS-00223 - OL09-00-000070 - SV-271454r1092458_rule + SRG-OS-000033-GPOS-00014 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + SRG-OS-000396-GPOS-00176 + SRG-OS-000423-GPOS-00187 + SRG-OS-000478-GPOS-00223 + OL09-00-000070 + SV-271454r1092458_rule Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. + @@ -5612,7 +6198,7 @@ configured according to elapsed time. Specify the time component of the rekey limit. The session key is renegotiated after the defined amount of time passes. The number is followed by units such as H or M for hours or minutes. Note that the RekeyLimit can -be also configured according to amount of transfered data. +be also configured according to amount of transferred data. 1h 1h @@ -5624,6 +6210,7 @@ be also configured according to amount of transfered data.DEFAULT:NO-SHA1 FIPS FIPS:OSPP + FIPS:STIG LEGACY FUTURE NEXT @@ -5634,9 +6221,6 @@ be also configured according to amount of transfered data. $ sudo yum install crypto-policies - CCI-002890 - CCI-002450 - CCI-003123 FCS_COP.1(1) FCS_COP.1(2) FCS_COP.1(3) @@ -5644,11 +6228,11 @@ $ sudo yum install crypto-policies FCS_CKM.1 FCS_CKM.2 FCS_TLSC_EXT.1 - SRG-OS-000396-GPOS-00176 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - OL09-00-000240 - SV-271477r1091143_rule + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + OL09-00-000240 + SV-271477r1091143_rule Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. @@ -5658,7 +6242,7 @@ if ! rpm -q --quiet "crypto-policies" ; then fi - name: Ensure crypto-policies is installed - package: + ansible.builtin.package: name: crypto-policies state: present tags: @@ -5705,17 +6289,15 @@ In the options section of /etc/named.confinclude "/etc/crypto-policies/back-ends/bind.config"; - CCI-002418 - CCI-002422 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-13 SC-12(2) SC-12(3) - SRG-OS-000423-GPOS-00187 - SRG-OS-000426-GPOS-00190 - OL09-00-002421 - SV-271759r1091989_rule + SRG-OS-000423-GPOS-00187 + SRG-OS-000426-GPOS-00190 + OL09-00-002421 + SV-271759r1091989_rule Overriding the system crypto policy makes the behavior of the BIND service violate expectations, and makes system configuration more fragmented. @@ -5845,22 +6427,14 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000068 - CCI-003123 - CCI-002450 - CCI-000877 - CCI-002418 - CCI-001453 - CCI-002890 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) 164.312(e)(1) 164.312(e)(2)(ii) - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) @@ -5875,23 +6449,26 @@ submits to this process. FCS_CKM.1 FCS_CKM.2 FCS_TLSC_EXT.1 - SRG-OS-000396-GPOS-00176 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 A.5.SEC-OL4 + 1446 2.2.7 2.2 - OL09-00-000070 - OL09-00-000241 - SV-271454r1092458_rule - SV-271478r1092620_rule + OL09-00-000070 + OL09-00-000241 + SV-271454r1092458_rule + SV-271478r1092620_rule Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. - + var_system_crypto_policy='' + + stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null) rc=$? @@ -5913,12 +6490,12 @@ fi tags: - always -- name: Configure System Cryptography Policy - lineinfile: - path: /etc/crypto-policies/config - regexp: ^(?!#)(\S+)$ - line: '{{ var_system_crypto_policy }}' - create: true +- name: Configure System Cryptography Policy - Check current crypto policy (runtime) + ansible.builtin.command: /usr/bin/update-crypto-policies --show + register: current_crypto_policy + changed_when: false + failed_when: false + check_mode: false tags: - DISA-STIG-OL09-00-000070 - DISA-STIG-OL09-00-000241 @@ -5938,8 +6515,90 @@ fi - no_reboot_needed - restrict_strategy -- name: Verify that Crypto Policy is Set (runtime) - command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy }} +- name: Configure System Cryptography Policy - Get mtime of /etc/crypto-policies/config + ansible.builtin.stat: + path: /etc/crypto-policies/config + register: config_file_stat + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure System Cryptography Policy - Get mtime of /etc/crypto-policies/state/current + ansible.builtin.stat: + path: /etc/crypto-policies/state/current + register: current_file_stat + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure System Cryptography Policy - Check existence of /etc/crypto-policies/back-ends/nss.config + ansible.builtin.stat: + path: /etc/crypto-policies/back-ends/nss.config + register: nss_config_stat + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure System Cryptography Policy - Verify that Crypto Policy is Set (runtime) + ansible.builtin.command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy + }} + when: (current_crypto_policy.stdout.strip() != var_system_crypto_policy) or (config_file_stat.stat.exists + and current_file_stat.stat.exists and config_file_stat.stat.mtime > current_file_stat.stat.mtime) + or (not nss_config_stat.stat.exists) tags: - DISA-STIG-OL09-00-000070 - DISA-STIG-OL09-00-000241 @@ -5975,18 +6634,17 @@ set up to ignore it. To check that Crypto Policies settings for Kerberos are configured correctly, examine that there is a symlink at /etc/krb5.conf.d/crypto-policies targeting /etc/cypto-policies/back-ends/krb5.config. If the symlink exists, Kerberos is configured to use the system-wide crypto policy settings. - CCI-000803 - 0418 - 1055 - 1402 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-13 SC-12(2) SC-12(3) - SRG-OS-000120-GPOS-00061 - OL09-00-002424 - SV-271762r1091998_rule + SRG-OS-000120-GPOS-00061 + 0418 + 1055 + 1402 + OL09-00-002424 + SV-271762r1091998_rule Overriding the system crypto policy makes the behavior of Kerberos violate expectations, and makes system configuration more fragmented. @@ -5994,7 +6652,7 @@ rm -f /etc/krb5.conf.d/crypto-policies ln -s /etc/crypto-policies/back-ends/krb5.config /etc/krb5.conf.d/crypto-policies - name: Configure Kerberos to use System Crypto Policy - file: + ansible.builtin.file: src: /etc/crypto-policies/back-ends/krb5.config path: /etc/krb5.conf.d/crypto-policies state: link @@ -6029,22 +6687,24 @@ In /etc/ipsec.conf, make sure that the following line is not commented out or superseded by later includes: include /etc/crypto-policies/back-ends/libreswan.config - CCI-000068 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 CM-6(a) MA-4(6) SC-13 SC-12(2) SC-12(3) Req-2.2 - SRG-OS-000033-GPOS-00014 - OL09-00-002404 - SV-271743r1092635_rule + SRG-OS-000033-GPOS-00014 + OL09-00-002404 + SV-271743r1092635_rule Overriding the system crypto policy makes the behavior of the Libreswan service violate expectations, and makes system configuration more fragmented. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + function remediate_libreswan_crypto_policy() { CONFIG_FILE="/etc/ipsec.conf" if ! grep -qP "^\s*include\s+/etc/crypto-policies/back-ends/libreswan.config\s*(?:#.*)?$" "$CONFIG_FILE" ; then @@ -6055,12 +6715,35 @@ function remediate_libreswan_crypto_policy() { } remediate_libreswan_crypto_policy + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure Libreswan to use System Crypto Policy - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002404 + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSS-Req-2.2 + - configure_libreswan_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure Libreswan to use System Crypto Policy + ansible.builtin.lineinfile: path: /etc/ipsec.conf line: include /etc/crypto-policies/back-ends/libreswan.config create: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002404 - NIST-800-53-CM-6(a) @@ -6092,10 +6775,9 @@ To check that Crypto Policies settings are configured correctly, you have to exa available under /etc/pki/tls/openssl.cnf. This file has the ini format, and it enables crypto policy support if there is a [ crypto_policy ] section that contains the .include = /etc/crypto-policies/back-ends/opensslcnf.config directive. - CCI-001453 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) @@ -6113,7 +6795,7 @@ if there is a [ crypto_policy ] section that contains the FCS_TLSC_EXT.1 FCS_TLSC_EXT.1.1 Req-2.2 - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 Overriding the system crypto policy makes the behavior of the Java runtime violates expectations, and makes system configuration more fragmented. @@ -6259,15 +6941,14 @@ set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the CRYPTO_POLICY variable is either commented or not set at all in the /etc/sysconfig/sshd. - CCI-001453 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) 164.312(e)(1) 164.312(e)(2)(ii) - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) @@ -6277,22 +6958,50 @@ in the /etc/sysconfig/sshd. FCS_SSHS_EXT.1 FCS_SSHC_EXT.1 Req-2.2 - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 A.5.SEC-OL6 + 0418 2.2.7 2.2 Overriding the system crypto policy makes the behavior of the SSH service violate expectations, and makes system configuration more fragmented. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + SSH_CONF="/etc/sysconfig/sshd" sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure SSH to use System Crypto Policy - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - PCI-DSS-Req-2.2 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_ssh_crypto_policy + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Configure SSH to use System Crypto Policy + ansible.builtin.lineinfile: dest: /etc/sysconfig/sshd state: absent regexp: (?i)^\s*CRYPTO_POLICY.*$ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(2) - NIST-800-53-AC-17(a) @@ -6322,18 +7031,18 @@ sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF To override the system wide crypto policy for Openssh client, place a file in the /etc/ssh/ssh_config.d/ so that it is loaded before the 05-redhat.conf. In this case it is file named 02-ospp.conf containing parameters which need to be changed with respect to the crypto policy. This rule checks if the file exists and if it contains required parameters and values which modify the Crypto Policy. During the parsing process, as soon as Openssh client parses some configuration option and its value, it remembers it and ignores any subsequent overrides. The customization mechanism provided by crypto policies appends eventual customizations at the end of the system wide crypto policy. Therefore, if the crypto policy customization overrides some parameter which is already configured in the system wide crypto policy, the SSH client will not honor that customized parameter. - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) MA-4(6) SC-13 - SRG-OS-000033-GPOS-00014 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 + SRG-OS-000033-GPOS-00014 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 The Common Criteria requirements specify how certain parameters for OpenSSH Client are configured. Particular parameters are RekeyLimit, GSSAPIAuthentication, Ciphers, PubkeyAcceptedKeyTypes, MACs and KexAlgorithms. Currently particular requirements specified by CC are stricter compared to any existing Crypto Policy. #the file starts with 02 so that it is loaded before the 05-redhat.conf which activates configuration provided by system vide crypto policy @@ -6382,21 +7091,39 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-001453 AC-17(2) - SRG-OS-000033-GPOS-00014 - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - SRG-OS-000423-GPOS-00187 - OL09-00-000261 - SV-271489r1092627_rule + SRG-OS-000033-GPOS-00014 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + SRG-OS-000423-GPOS-00187 + OL09-00-000261 + SV-271489r1092627_rule Overriding the system crypto policy makes the behavior of the OpenSSH client violate expectations, and makes system configuration more fragmented. By specifying a cipher list with the order of ciphers being in a “strongest to weakest” orientation, the system will automatically attempt to use the strongest cipher for securing SSH connections. + +sshd_approved_ciphers='' + + +if [ -e "/etc/crypto-policies/back-ends/openssh.config" ] ; then + + LC_ALL=C sed -i "/^.*Ciphers\s\+/d" "/etc/crypto-policies/back-ends/openssh.config" +else + touch "/etc/crypto-policies/back-ends/openssh.config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/crypto-policies/back-ends/openssh.config" + +cp "/etc/crypto-policies/back-ends/openssh.config" "/etc/crypto-policies/back-ends/openssh.config.bak" +# Insert at the end of the file +printf '%s\n' "Ciphers ${sshd_approved_ciphers}" >> "/etc/crypto-policies/back-ends/openssh.config" +# Clean up after ourselves. +rm "/etc/crypto-policies/back-ends/openssh.config.bak" + - name: XCCDF Value sshd_approved_ciphers # promote to variable set_fact: sshd_approved_ciphers: !!str @@ -6407,7 +7134,7 @@ strongest cipher for securing SSH connections. block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/crypto-policies/back-ends/openssh.config create: true regexp: (?i)^.*Ciphers\s+ @@ -6417,7 +7144,7 @@ strongest cipher for securing SSH connections. register: dupes - name: Deduplicate values from /etc/crypto-policies/back-ends/openssh.config - lineinfile: + ansible.builtin.lineinfile: path: /etc/crypto-policies/back-ends/openssh.config create: true regexp: (?i)^.*Ciphers\s+ @@ -6425,7 +7152,7 @@ strongest cipher for securing SSH connections. when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/crypto-policies/back-ends/openssh.config - lineinfile: + ansible.builtin.lineinfile: path: /etc/crypto-policies/back-ends/openssh.config create: true regexp: (?i)^.*Ciphers\s+ @@ -6478,17 +7205,17 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-001453 AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - OL09-00-000254 - SV-271485r1092625_rule + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000254 + SV-271485r1092625_rule Overriding the system crypto policy makes the behavior of the OpenSSH server violate expectations, and makes system configuration more fragmented. By specifying a cipher list with the order of ciphers being in a “strongest to weakest” orientation, the system will automatically attempt to use the strongest cipher for securing SSH connections. + @@ -6526,14 +7253,77 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000877 - CCI-001453 AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000262 + SV-271490r1092628_rule Overriding the system crypto policy makes the behavior of the OpenSSH client violate expectations, and makes system configuration more fragmented. + +sshd_approved_macs='' + + +if [ -e "/etc/crypto-policies/back-ends/openssh.config" ] ; then + + LC_ALL=C sed -i "/^.*MACs\s\+/d" "/etc/crypto-policies/back-ends/openssh.config" +else + touch "/etc/crypto-policies/back-ends/openssh.config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/crypto-policies/back-ends/openssh.config" + +cp "/etc/crypto-policies/back-ends/openssh.config" "/etc/crypto-policies/back-ends/openssh.config.bak" +# Insert at the end of the file +printf '%s\n' "MACs ${sshd_approved_macs}" >> "/etc/crypto-policies/back-ends/openssh.config" +# Clean up after ourselves. +rm "/etc/crypto-policies/back-ends/openssh.config.bak" + + - name: XCCDF Value sshd_approved_macs # promote to variable + set_fact: + sshd_approved_macs: !!str + tags: + - always + +- name: 'Configure SSH Daemon to Use FIPS 140-2 Validated MACs: openssh.config' + block: + + - name: Check for duplicate values + ansible.builtin.lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*MACs\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/crypto-policies/back-ends/openssh.config + ansible.builtin.lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*MACs\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/crypto-policies/back-ends/openssh.config + ansible.builtin.lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*MACs\s+ + line: MACs {{ sshd_approved_macs }} + state: present + tags: + - DISA-STIG-OL09-00-000262 + - NIST-800-53-AC-17(2) + - harden_sshd_macs_openssh_conf_crypto_policy + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + @@ -6571,14 +7361,15 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000877 - CCI-001453 AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000255 + SV-271486r1092626_rule Overriding the system crypto policy makes the behavior of the OpenSSH server violate expectations, and makes system configuration more fragmented. + @@ -6613,7 +7404,6 @@ Linux vendor, Oracle Corporation is responsible for providing security patches.< BAI03.10 DSS05.01 DSS05.02 - CCI-000366 4.2.3 4.2.3.12 4.2.3.7 @@ -6628,9 +7418,9 @@ Linux vendor, Oracle Corporation is responsible for providing security patches.< SA-13(a) ID.RA-1 PR.IP-12 - SRG-OS-000480-GPOS-00227 - OL09-00-000010 - SV-271438r1091026_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000010 + SV-271438r1117152_rule An operating system is considered "supported" if the vendor continues to provide security patches for the product. With an unsupported release, it will not be possible to resolve any security issue discovered in the system @@ -6677,7 +7467,7 @@ used to monitor, detect, and defend computer networks and systems. Install McAfee Endpoint Security for Linux (ENSL) Install McAfee Endpoint Security for Linux antivirus software -which is provided for DoD systems and uses signatures to search for the +which is provided for systems and uses signatures to search for the presence of viruses on the filesystem. The McAfeeTP package can be installed with the following command: @@ -6686,10 +7476,8 @@ $ sudo yum install McAfeeTP Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, automated remediation is not available for this configuration check. - CCI-001263 - CCI-000366 SI-2(2) - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 Virus scanning software can be used to detect if a system has been compromised by computer viruses, as well as to limit their spread to other systems. @@ -6702,14 +7490,12 @@ computer viruses, as well as to limit their spread to other systems. Ensure McAfee Endpoint Security for Linux (ENSL) is running Install McAfee Endpoint Security for Linux antivirus software -which is provided for DoD systems and uses signatures to search for the +which is provided for systems and uses signatures to search for the presence of viruses on the filesystem. Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, automated remediation is not available for this configuration check. - CCI-001263 - CCI-000366 SI-2(2) - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 Virus scanning software can be used to detect if a system has been compromised by computer viruses, as well as to limit their spread to other systems. @@ -6780,6 +7566,8 @@ Detailed information on encrypting partitions using LUKS or LUKS ciphers can be the Oracle Linux 9 Documentation web site: https://docs.oracle.com/en/operating-systems/oracle-linux/9/install/install-InstallingOracleLinuxManually.html#system-options . + Due to different needs, possibilities, and passphrase requirement automated remediation is +not available for this configuration check. 13 14 APO01.06 @@ -6792,9 +7580,6 @@ the Oracle Linux 9 Documentation web site: DSS06.02 DSS06.06 3.13.16 - CCI-002476 - CCI-001199 - CCI-002475 164.308(a)(1)(ii)(D) 164.308(b)(1) 164.310(d) @@ -6831,8 +7616,8 @@ the Oracle Linux 9 Documentation web site: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 CM-6(a) SC-28 SC-28(1) @@ -6840,17 +7625,20 @@ the Oracle Linux 9 Documentation web site: AU-9(3) PR.DS-1 PR.DS-5 - SRG-OS-000405-GPOS-00184 - SRG-OS-000185-GPOS-00079 - SRG-OS-000404-GPOS-00183 + SRG-OS-000405-GPOS-00184 + SRG-OS-000185-GPOS-00079 + SRG-OS-000404-GPOS-00183 A.25.SEC-OL1 - OL09-00-000001 - OL09-00-002418 - SV-271431r1092616_rule - SV-271756r1091980_rule + OL09-00-000001 + OL09-00-002418 + SV-271431r1092616_rule + SV-271756r1091980_rule The risk of a system's physical compromise, particularly mobile systems such as laptops, places its data at risk of compromise. Encrypting this data mitigates the risk of its loss if the system is lost. + + + @@ -6861,7 +7649,7 @@ the risk of its loss if the system is lost. One program will create a memory portion, which other processes (if permitted) can access. If /dev/shm is not configured, tmpfs will be mounted to /dev/shm by systemd. - This rule does not have a remedation. + This rule does not have a remediation. It is expected that this will be managed by systemd and will be a tmpfs partition. Any user can upload and execute files inside the /dev/shm similar to the /tmp partition. Configuring /dev/shm allows an administrator @@ -6890,7 +7678,6 @@ mountpoint can instead be configured later. 8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -6907,10 +7694,10 @@ mountpoint can instead be configured later. CM-6(a) SC-5(2) PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000003 - SV-271433r1091011_rule + OL09-00-000003 + SV-271433r1091011_rule Ensuring that /home is mounted on its own partition enables the setting of more restrictive mount options, and also helps ensure that users cannot trivially fill partitions used for log or audit data storage. @@ -6956,7 +7743,6 @@ logical volume at installation time, or migrate it using LVM.8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -6973,9 +7759,9 @@ logical volume at installation time, or migrate it using LVM.CM-6(a) SC-5(2) PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-000004 - SV-271434r1091014_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000004 + SV-271434r1091014_rule The /tmp partition is used as temporary storage by many programs. Placing /tmp in its own partition enables the setting of more restrictive mount options, which can help protect programs which use it. @@ -6999,7 +7785,6 @@ or logical volume at installation time, or migrate it using LVM.8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -7016,10 +7801,10 @@ or logical volume at installation time, or migrate it using LVM.CM-6(a) SC-5(2) PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000005 - SV-271435r1091017_rule + OL09-00-000005 + SV-271435r1091017_rule Ensuring that /var is mounted on its own partition enables the setting of more restrictive mount options. This helps protect system services such as daemons or other programs which use it. @@ -7057,7 +7842,6 @@ volume at installation time, or migrate it using LVM. DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -7087,16 +7871,16 @@ volume at installation time, or migrate it using LVM. A.13.1.1 A.13.2.1 A.14.1.3 - CIP-007-3 R6.5 + CIP-007-3 R6.5 CM-6(a) AU-4 SC-5(2) PR.PT-1 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000006 - SV-271436r1091020_rule + OL09-00-000006 + SV-271436r1091020_rule Placing /var/log in its own partition enables better separation between log files and other files in /var/. @@ -7137,8 +7921,6 @@ audit logs that will be created by the auditing daemon. DSS05.04 DSS05.07 MEA02.01 - CCI-000366 - CCI-001849 164.312(a)(2)(ii) 4.3.3.3.9 4.3.3.5.8 @@ -7172,7 +7954,7 @@ audit logs that will be created by the auditing daemon. A.13.2.1 A.14.1.3 A.17.2.1 - CIP-007-3 R6.5 + CIP-007-3 R6.5 CM-6(a) AU-4 SC-5(2) @@ -7180,12 +7962,12 @@ audit logs that will be created by the auditing daemon. PR.PT-1 PR.PT-4 FMT_SMF_EXT.1 - SRG-OS-000341-GPOS-00132 - SRG-OS-000480-GPOS-00227 - SRG-APP-000357-CTR-000800 + SRG-OS-000341-GPOS-00132 + SRG-OS-000480-GPOS-00227 + SRG-APP-000357-CTR-000800 R71 - OL09-00-000002 - SV-271432r1091008_rule + OL09-00-000002 + SV-271432r1091008_rule Placing /var/log/audit in its own partition enables better separation between audit files and other files, and helps ensure that @@ -7206,11 +7988,10 @@ part /var/log/audit The /var/tmp directory is a world-writable directory used for temporary file storage. Ensure it has its own partition or logical volume at installation time, or migrate it using LVM. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000007 - SV-271437r1091023_rule + OL09-00-000007 + SV-271437r1091023_rule The /var/tmp partition is used as temporary storage by many programs. Placing /var/tmp in its own partition enables the setting of more restrictive mount options, which can help protect programs which use it. @@ -7236,7 +8017,7 @@ restrictive mount options, which can help protect programs which use it. The tmp.mount unit configures the tmpfs filesystem and ensures the /tmp directory is wiped during reboot. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'tmp.mount' @@ -7268,8 +8049,8 @@ fi masked: 'false' when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - enable_strategy - low_complexity @@ -7314,16 +8095,15 @@ in the following directories: /etc/dconf/db/local.d /etc/dconf/db/local.d - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(5)(ii)(A) Req-6.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 reload_dconf_db 8.2.8 8.2 - OL09-00-002162 - SV-271692r1091788_rule + OL09-00-002162 + SV-271692r1091788_rule Unlike text-based keyfiles, the binary database is impossible to check by OVAL. Therefore, in order to evaluate dconf configuration, both have to be true at the same time - configuration files have to be compliant, and the database needs to be more recent than those keyfiles, @@ -7353,12 +8133,55 @@ fi - no_reboot_needed - unknown_strategy -- name: Run dconf update +- name: Make sure that the dconf databases are up-to-date with regards to respective + keyfiles - Get database modification time for local + ansible.builtin.stat: + path: /etc/dconf/db/local + register: local_db + when: + - '"gdm" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002162 + - PCI-DSS-Req-6.2 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - dconf_db_up_to_date + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - unknown_strategy + +- name: Make sure that the dconf databases are up-to-date with regards to respective + keyfiles - Get keyfiles for local + ansible.builtin.find: + paths: /etc/dconf/db/local.d/ + register: local_keyfiles + when: + - '"gdm" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002162 + - PCI-DSS-Req-6.2 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - dconf_db_up_to_date + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - unknown_strategy + +- name: Make sure that the dconf databases are up-to-date with regards to respective + keyfiles - Run dconf update for local ansible.builtin.command: cmd: dconf update when: - '"gdm" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not local_db.stat.exists or local_keyfiles.files | length > 0 and local_keyfiles.files + | map(attribute='mtime') | max > local_db.stat.mtime tags: - DISA-STIG-OL09-00-002162 - PCI-DSS-Req-6.2 @@ -7395,6 +8218,8 @@ system-db:site system-db:distro + 8.2.8 + 8.2 Failure to have a functional DConf profile prevents GNOME3 configuration settings from being enforced for all users and allows various security risks. @@ -7448,7 +8273,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.02 3.1.2 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -7480,17 +8304,16 @@ After the settings have been set, run dconf update.CM-7(b) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002127 - OL09-00-002128 - SV-271685r1091767_rule - SV-271686r1091770_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002127 + OL09-00-002128 + SV-271685r1091767_rule + SV-271686r1091770_rule A user who is at the console can reboot the system at the login screen. If restart or shutdown buttons are pressed at the login screen, this can create the risk of short-term loss of availability of systems due to reboot. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -7567,16 +8390,15 @@ fi - unknown_strategy - name: Disable the GNOME3 Login Restart and Shutdown Buttons - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: disable-restart-buttons value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002127 - DISA-STIG-OL09-00-002128 @@ -7593,14 +8415,13 @@ fi - name: Prevent user modification of GNOME disablement of Login Restart and Shutdown Buttons - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/disable-restart-buttons line: /org/gnome/login-screen/disable-restart-buttons create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002127 - DISA-STIG-OL09-00-002128 @@ -7616,10 +8437,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002127 - DISA-STIG-OL09-00-002128 @@ -7658,19 +8479,17 @@ Once the setting has been added, add a lock to user modification. For example: /org/gnome/login-screen/disable-user-list After the settings have been set, run dconf update. - CCI-000366 CM-6(a) AC-23 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL9 - OL09-00-002102 - SV-271672r1092631_rule + OL09-00-002102 + SV-271672r1092631_rule Leaving the user list enabled is a security risk since it allows anyone with physical access to the system to quickly enumerate known user accounts without logging in. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -7744,16 +8563,15 @@ fi - unknown_strategy - name: Disable the GNOME3 Login User List - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: disable-user-list value: 'true' no_extra_spaces: true create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 @@ -7766,14 +8584,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 disablement of Login User List - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/disable-user-list$ line: /org/gnome/login-screen/disable-user-list create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 @@ -7786,10 +8603,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 @@ -7824,19 +8641,16 @@ Once the setting has been added, add a lock to For example: /org/gnome/settings-daemon/peripherals/smartcard/removal-action After the settings have been set, run dconf update. - CCI-000057 - CCI-000056 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - OL09-00-002160 - OL09-00-002126 - SV-271690r1092634_rule - SV-271684r1091764_rule + SRG-OS-000028-GPOS-00009 + SRG-OS-000030-GPOS-00011 + OL09-00-002160 + OL09-00-002126 + SV-271690r1092634_rule + SV-271684r1091764_rule Locking the screen automatically when removing the smartcard can prevent undesired access to system. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -7909,13 +8723,11 @@ fi - unknown_strategy - name: Detect if removal-action can be found on /etc/dconf/db/local.d/ - find: + ansible.builtin.find: path: /etc/dconf/db/local.d/ contains: ^\s*removal-action register: dconf_gnome_lock_screen_on_smartcard_removal_config_files - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7927,7 +8739,7 @@ fi - unknown_strategy - name: Configure removal-action - default file - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d//00-security-settings section: org/gnome/settings-daemon/peripherals/smartcard option: removal-action @@ -7935,9 +8747,9 @@ fi create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_config_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_config_files.matched == 0 + register: default_file tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7949,7 +8761,7 @@ fi - unknown_strategy - name: Configure removal-action - existing files - ini_file: + community.general.ini_file: dest: '{{ item.path }}' section: org/gnome/settings-daemon/peripherals/smartcard option: removal-action @@ -7959,9 +8771,9 @@ fi }}' when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_config_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_config_files.matched > 0 + register: existing_files tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7973,13 +8785,11 @@ fi - unknown_strategy - name: Detect if lock for removal-action can be found on /etc/dconf/db/local.d/ - find: + ansible.builtin.find: path: /etc/dconf/db/local.d/locks contains: ^\s*removal-action register: dconf_gnome_lock_screen_on_smartcard_removal_lock_files - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7991,14 +8801,13 @@ fi - unknown_strategy - name: Prevent user modification removal-action - default file - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ line: /org/gnome/settings-daemon/peripherals/smartcard/removal-action create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_lock_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_lock_files.matched == 0 tags: @@ -8012,7 +8821,7 @@ fi - unknown_strategy - name: Prevent user modification removal-action - existing files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ line: /org/gnome/settings-daemon/peripherals/smartcard/removal-action @@ -8020,7 +8829,6 @@ fi with_items: '{{ dconf_gnome_lock_screen_on_smartcard_removal_lock_files.files }}' when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_lock_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_lock_files.matched > 0 tags: @@ -8034,10 +8842,10 @@ fi - unknown_strategy - name: Dconf Update - removal-action - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - default_file is changed or existing_files is changed tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -8073,7 +8881,6 @@ AutomaticLoginEnable=false BAI10.03 BAI10.05 3.1.1 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -8087,16 +8894,15 @@ AutomaticLoginEnable=false AC-6(1) CM-7(b) PR.IP-1 - SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00229 8.3.1 8.3 - OL09-00-002161 - SV-271691r1091785_rule + OL09-00-002161 + SV-271691r1091785_rule Failure to restrict system access to authenticated users negatively impacts operating system security. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then if rpm --quiet -q gdm then @@ -8132,16 +8938,14 @@ fi - unknown_strategy - name: Disable GDM Automatic Login - ini_file: + community.general.ini_file: dest: /etc/gdm/custom.conf section: daemon option: AutomaticLoginEnable value: 'false' no_extra_spaces: true create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002161 - NIST-800-171-3.1.1 @@ -8214,7 +9018,7 @@ fi - unknown_strategy - name: Disable XDMCP in GDM - ini_file: + community.general.ini_file: path: /etc/gdm/custom.conf section: xdmcp option: Enable @@ -8265,9 +9069,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.03 3.1.7 - CCI-000366 - CCI-000778 - CCI-001958 4.3.3.2.2 4.3.3.5.2 4.3.3.6.6 @@ -8293,9 +9094,9 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-3 PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL12 3.4.2 3.4 @@ -8303,9 +9104,8 @@ After the settings have been set, run dconf update. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -8382,16 +9182,15 @@ fi - unknown_strategy - name: Disable GNOME3 Automounting - automount - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/media-handling option: automount value: 'false' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) @@ -8407,14 +9206,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Automounting - automount - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/media-handling/automount$ line: /org/gnome/desktop/media-handling/automount create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) @@ -8430,10 +9228,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) @@ -8479,9 +9277,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.03 3.1.7 - CCI-000778 - CCI-000366 - CCI-001958 4.3.3.2.2 4.3.3.5.2 4.3.3.6.6 @@ -8507,24 +9302,23 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-3 PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL12 3.4.2 3.4 - OL09-00-002100 - OL09-00-002120 - SV-271670r1091722_rule - SV-271678r1091746_rule + OL09-00-002100 + OL09-00-002120 + SV-271670r1091722_rule + SV-271678r1091746_rule Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mounting in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -8603,16 +9397,15 @@ fi - unknown_strategy - name: Disable GNOME3 Automounting - automount-open - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/media-handling option: automount-open value: 'false' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002100 - DISA-STIG-OL09-00-002120 @@ -8630,14 +9423,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Automounting - automount-open - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/media-handling/automount-open$ line: /org/gnome/desktop/media-handling/automount-open create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002100 - DISA-STIG-OL09-00-002120 @@ -8655,10 +9447,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002100 - DISA-STIG-OL09-00-002120 @@ -8706,10 +9498,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.03 3.1.7 - CCI-000366 - CCI-001764 - CCI-001958 - CCI-000778 4.3.3.2.2 4.3.3.5.2 4.3.3.6.6 @@ -8735,22 +9523,21 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-3 PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL12 - OL09-00-002101 - OL09-00-002121 - SV-271671r1091725_rule - SV-271679r1091749_rule + OL09-00-002101 + OL09-00-002121 + SV-271671r1091725_rule + SV-271679r1091749_rule Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mount running in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -8827,16 +9614,15 @@ fi - unknown_strategy - name: Disable GNOME3 Automounting - autorun-never - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/media-handling option: autorun-never value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002101 - DISA-STIG-OL09-00-002121 @@ -8852,14 +9638,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Automounting - autorun-never - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/media-handling/autorun-never$ line: /org/gnome/desktop/media-handling/autorun-never create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002101 - DISA-STIG-OL09-00-002121 @@ -8875,10 +9660,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002101 - DISA-STIG-OL09-00-002121 @@ -8927,9 +9712,8 @@ After the settings have been set, run dconf update.164.312(e)(2)(ii) Username and password prompting is required for remote access. Otherwise, non-authorized and nefarious users can access the system freely. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -9001,16 +9785,15 @@ fi - unknown_strategy - name: Require Credential Prompting for Remote Access in GNOME3 - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/Vino option: authentication-methods value: '[''vnc'']' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.12 - dconf_gnome_remote_access_credential_prompt @@ -9021,14 +9804,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Credential Prompting for Remote Access - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/Vino/authentication-methods$ line: /org/gnome/Vino/authentication-methods create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.12 - dconf_gnome_remote_access_credential_prompt @@ -9039,10 +9821,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - NIST-800-171-3.1.12 - dconf_gnome_remote_access_credential_prompt @@ -9093,7 +9875,6 @@ After the settings have been set, run dconf update.BAI10.05 DSS03.01 3.1.13 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -9120,12 +9901,11 @@ After the settings have been set, run dconf update.DE.AE-1 PR.DS-7 PR.IP-1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Open X displays allow an attacker to capture keystrokes and to execute commands remotely. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -9200,16 +9980,15 @@ fi - unknown_strategy - name: Require Encryption for Remote Access in GNOME3 - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/Vino option: require-encryption value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.13 - NIST-800-53-AC-17(2) @@ -9223,14 +10002,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Encryption for Remote Access - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/Vino/require-encryption$ line: /org/gnome/Vino/require-encryption create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.13 - NIST-800-53-AC-17(2) @@ -9244,10 +10022,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - NIST-800-171-3.1.13 - NIST-800-53-AC-17(2) @@ -9330,7 +10108,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9357,7 +10134,7 @@ After the settings have been set, run dconf update.AC-11(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 + SRG-OS-000029-GPOS-00010 8.2.8 8.2 A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate @@ -9372,9 +10149,8 @@ be activated after the idle delay. Applications requiring continuous, real-time screen display (such as network management products) require the login session does not have administrator rights and the display station is located in a controlled-access area. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -9452,16 +10228,15 @@ fi - unknown_strategy - name: Enable GNOME3 Screensaver Idle Activation - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: idle-activation-enabled value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - NIST-800-171-3.1.10 @@ -9478,14 +10253,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME idle-activation-enabled - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/idle-activation-enabled$ line: /org/gnome/desktop/screensaver/idle-activation-enabled create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - NIST-800-171-3.1.10 @@ -9502,10 +10276,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - CJIS-5.5.5 - NIST-800-171-3.1.10 @@ -9549,8 +10323,6 @@ idle-delay=uint32 900 DSS05.10 DSS06.10 3.1.10 - CCI-000057 - CCI-000060 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9577,21 +10349,20 @@ idle-delay=uint32 900 CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 A.11.SEC-OL7 8.2.8 8.2 - OL09-00-002104 - SV-271674r1091734_rule + OL09-00-002104 + SV-271674r1091734_rule A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME3 can be configured to identify when a user's session has idled and take action to initiate a session lock. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then inactivity_timeout_value='' @@ -9660,16 +10431,15 @@ fi - always - name: Set GNOME3 Screensaver Inactivity Timeout - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/session option: idle-delay value: uint32 {{ inactivity_timeout_value }} create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002104 @@ -9687,10 +10457,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002104 @@ -9733,7 +10503,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9760,18 +10529,17 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 A.11.SEC-OL7 8.2.8 8.2 - OL09-00-002103 - SV-271673r1091731_rule + OL09-00-002103 + SV-271673r1091731_rule A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - +of the information system but does not want to logout because of the temporary nature of the absence. # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then var_screensaver_lock_delay='' @@ -9839,16 +10607,15 @@ fi - always - name: Set GNOME3 Screensaver Lock Delay After Activation Period - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: lock-delay value: uint32 {{ var_screensaver_lock_delay }} create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 @@ -9865,10 +10632,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed tags: - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 @@ -9915,8 +10682,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 - CCI-000056 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9942,17 +10707,16 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 + SRG-OS-000028-GPOS-00009 + SRG-OS-000030-GPOS-00011 8.2.8 8.2 - OL09-00-002123 - SV-271681r1091755_rule + OL09-00-002123 + SV-271681r1091755_rule A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - +of the information system but does not want to logout because of the temporary nature of the absence. # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -10029,29 +10793,9 @@ fi - no_reboot_needed - unknown_strategy -- name: Dconf Update - command: dconf update - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_distribution == 'SLES' - tags: - - CJIS-5.5.5 - - DISA-STIG-OL09-00-002123 - - NIST-800-171-3.1.10 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2 - - PCI-DSSv4-8.2.8 - - dconf_gnome_screensaver_lock_enabled - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - -- name: Enable GNOME3 Screensaver Lock After Idle Period - ini_file: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Enable GNOME3 Screensaver + Lock After Idle Period + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: lock-enabled @@ -10060,8 +10804,8 @@ fi no_extra_spaces: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution != 'SLES' + register: screensaver_config tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10077,16 +10821,17 @@ fi - no_reboot_needed - unknown_strategy -- name: Prevent user modification of GNOME lock-enabled - lineinfile: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Prevent user modification + of GNOME lock-enabled + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/lock-enabled$ line: /org/gnome/desktop/screensaver/lock-enabled create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution != 'SLES' + register: screensaver_lock tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10102,8 +10847,9 @@ fi - no_reboot_needed - unknown_strategy -- name: Enable GNOME3 Screensaver Lock After Idle Period - ini_file: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Enable GNOME3 Screensaver + Lock After Idle Period + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/lockdown option: disable-lock-screen @@ -10112,8 +10858,8 @@ fi no_extra_spaces: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + register: lockdown_config tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10129,16 +10875,17 @@ fi - no_reboot_needed - unknown_strategy -- name: Prevent user modification of GNOME disable-lock-screen - lineinfile: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Prevent user modification + of GNOME disable-lock-screen + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/lockdown/disable-lock-screen$ line: /org/gnome/desktop/lockdown/disable-lock-screen create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + register: lockdown_lock tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10154,13 +10901,14 @@ fi - no_reboot_needed - unknown_strategy -- name: Check GNOME3 screenserver disable-lock-screen false - command: gsettings get org.gnome.desktop.lockdown disable-lock-screen +- name: Enable GNOME3 Screensaver Lock After Idle Period - Check GNOME3 screenserver + disable-lock-screen false + ansible.builtin.command: gsettings get org.gnome.desktop.lockdown disable-lock-screen register: cmd_out when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + changed_when: false tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10176,12 +10924,14 @@ fi - no_reboot_needed - unknown_strategy -- name: Update GNOME3 screenserver disable-lock-screen false - command: gsettings set org.gnome.desktop.lockdown disable-lock-screen false +- name: Enable GNOME3 Screensaver Lock After Idle Period - Update GNOME3 screenserver + disable-lock-screen false + ansible.builtin.command: gsettings set org.gnome.desktop.lockdown disable-lock-screen + false when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + - cmd_out.stdout != 'false' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10197,11 +10947,35 @@ fi - no_reboot_needed - unknown_strategy -- name: Dconf Update - command: dconf update +- name: Enable GNOME3 Screensaver Lock After Idle Period - Update dconf database for + non-SLES systems + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ansible_distribution != 'SLES' + - (screensaver_config is changed or screensaver_lock is changed) + tags: + - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 + - NIST-800-171-3.1.10 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - dconf_gnome_screensaver_lock_enabled + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Enable GNOME3 Screensaver Lock After Idle Period - Update dconf database for + SLES systems + ansible.builtin.command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - ansible_distribution == 'SLES' + - (lockdown_config is changed or lockdown_lock is changed) tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10249,7 +11023,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000060 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -10277,16 +11050,15 @@ After the settings have been set, run dconf update.AC-11(1).1 PR.AC-7 Req-8.1.8 - SRG-OS-000031-GPOS-00012 + SRG-OS-000031-GPOS-00012 8.2.8 8.2 - OL09-00-002106 - SV-271676r1091740_rule + OL09-00-002106 + SV-271676r1091740_rule Setting the screensaver mode to blank-only conceals the contents of the display from passersby. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -10366,16 +11138,15 @@ fi - unknown_strategy - name: Implement Blank Screensaver - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: picture-uri value: string '' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002106 @@ -10394,14 +11165,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME picture-uri - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/picture-uri$ line: /org/gnome/desktop/screensaver/picture-uri create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002106 @@ -10420,10 +11190,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002106 @@ -10464,7 +11234,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -10489,18 +11258,17 @@ After the settings have been set, run dconf update.A.9.4.3 CM-6(a) PR.AC-7 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - OL09-00-002125 - SV-271683r1091761_rule + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 + OL09-00-002125 + SV-271683r1091761_rule A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. As such, users should not be allowed to change session settings. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/lock-delay$" "/etc/dconf/db/" \ @@ -10540,14 +11308,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME lock-delay - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/lock-delay$ line: /org/gnome/desktop/screensaver/lock-delay create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 @@ -10560,10 +11327,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_lineinfile is changed tags: - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 @@ -10598,8 +11365,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 - CCI-000060 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -10625,20 +11390,19 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 8.2.8 8.2 - OL09-00-002124 - SV-271682r1091758_rule + OL09-00-002124 + SV-271682r1091758_rule A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. As such, users should not be allowed to change session settings. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/session/idle-delay$" "/etc/dconf/db/" \ @@ -10681,14 +11445,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME Session idle-delay - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/session/idle-delay$ line: /org/gnome/desktop/session/idle-delay create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 @@ -10704,10 +11467,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_lineinfile is changed tags: - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 @@ -10733,10 +11496,10 @@ fi GNOME System Settings GNOME provides configuration and functionality to a graphical desktop environment -that changes grahical configurations or allow a user to perform +that changes graphical configurations or allow a user to perform actions that users normally would not be able to do in non-graphical mode such as remote access configuration, power policies, Geo-location, etc. -Configuring such settings in GNOME will prevent accidential graphical configuration +Configuring such settings in GNOME will prevent accidental graphical configuration changes by users from taking place. Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 @@ -10768,7 +11531,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.02 3.1.2 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -10800,18 +11562,17 @@ After the settings have been set, run dconf update.CM-7(b) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002107 - OL09-00-002129 - SV-271677r1091743_rule - SV-271687r1091773_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002107 + OL09-00-002129 + SV-271677r1091743_rule + SV-271687r1091773_rule A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term loss of availability of systems due to unintentional reboot. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -10888,16 +11649,15 @@ fi - unknown_strategy - name: Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/settings-daemon/plugins/media-keys option: logout value: '['''']' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002107 - DISA-STIG-OL09-00-002129 @@ -10913,14 +11673,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME disablement of Ctrl-Alt-Del - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/settings-daemon/plugins/media-keys/logout$ line: /org/gnome/settings-daemon/plugins/media-keys/logout create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002107 - DISA-STIG-OL09-00-002129 @@ -10936,10 +11695,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002107 - DISA-STIG-OL09-00-002129 @@ -10973,6 +11732,7 @@ that normally only root is allowed to execute. For more information on Sudo and addition Sudo configuration options, see https://www.sudo.ws. + Group name dedicated to the use of sudo Specify the name of the group that should own /usr/bin/sudo. @@ -11017,23 +11777,19 @@ running a command. $ sudo yum install sudo - CCI-002235 - 1382 - 1384 - 1386 CM-6(a) FMT_MOF_EXT.1 - SRG-OS-000324-GPOS-00125 + SRG-OS-000324-GPOS-00125 R33 + 1386 2.2.6 2.2 - OL09-00-000230 - SV-271474r1091134_rule + OL09-00-000230 + SV-271474r1091134_rule sudo is a program designed to allow a system administrator to give limited root privileges to users and log root activity. The basic philosophy is to give as few privileges as possible but still allow system users to get their work done. - # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -11061,7 +11817,7 @@ fi - package_sudo_installed - name: Ensure sudo is installed - package: + ansible.builtin.package: name: sudo state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -11102,20 +11858,81 @@ version = "*" Verify Group Who Owns /etc/sudoers.d Directory - To properly set the group owner of /etc/sudoers.d, run the command: $ sudo chgrp root /etc/sudoers.d + To properly set the group owner of /etc/sudoers.d, run the command: +$ sudo chgrp root /etc/sudoers.d R50 The ownership of the /etc/sudoers.d directory by the root group is important because this directory hosts sudo configuration. Protection of this directory is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - find -H /etc/sudoers.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/sudoers.d/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure group owner on /etc/sudoers.d/ - file: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - directory_groupowner_etc_sudoersd_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_sudoersd_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_sudoersd_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/sudoers.d/ + ansible.builtin.file: path: /etc/sudoers.d/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_sudoersd_newgroup }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_groupowner_etc_sudoersd @@ -11133,20 +11950,63 @@ ensures exclusive control of the sudo configuration. Verify User Who Owns /etc/sudoers.d Directory - To properly set the owner of /etc/sudoers.d, run the command: $ sudo chown root /etc/sudoers.d + To properly set the owner of /etc/sudoers.d, run the command: +$ sudo chown root /etc/sudoers.d R50 The ownership of the /etc/sudoers.d directory by the root user is important because this directory hosts sudo configuration. Protection of this directory is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - find -H /etc/sudoers.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/sudoers.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure owner on directory /etc/sudoers.d/ - file: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_owner_etc_sudoersd_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_sudoersd_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/sudoers.d/ + ansible.builtin.file: path: /etc/sudoers.d/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_sudoersd_newown }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_owner_etc_sudoersd @@ -11171,18 +12031,34 @@ ensures exclusive control of the sudo configuration. because this directory hosts sudo configuration. Protection of this directory is critical for system security. Restricting the permissions ensures exclusive control of the sudo configuration. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +find -H /etc/sudoers.d/ -maxdepth 0 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u-s,g-ws,o-xwrt {} \; - -find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u-s,g-ws,o-xwrt {} \; +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ file(s) - command: 'find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d ' + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/sudoers.d/ file(s) + ansible.builtin.command: 'find -P /etc/sudoers.d/ -maxdepth 0 -perm /u+s,g+ws,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_permissions_etc_sudoersd @@ -11192,12 +12068,13 @@ find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u - no_reboot_needed - name: Set permissions for /etc/sudoers.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-xwrt state: directory with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_permissions_etc_sudoersd @@ -11215,19 +12092,38 @@ find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u Verify Group Who Owns /etc/sudoers File - To properly set the group owner of /etc/sudoers, run the command: $ sudo chgrp root /etc/sudoers + To properly set the group owner of /etc/sudoers, run the command: +$ sudo chgrp root /etc/sudoers R50 The ownership of the /etc/sudoers file by the root group is important because this file hosts sudo configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - chgrp root /etc/sudoers + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/sudoers" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/sudoers +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/sudoers - stat: - path: /etc/sudoers - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_groupowner_etc_sudoers @@ -11236,11 +12132,57 @@ ensures exclusive control of the sudo configuration. - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/sudoers - file: +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_sudoers_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_sudoers_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_sudoers_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sudoers + ansible.builtin.stat: path: /etc/sudoers - group: root - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/sudoers + ansible.builtin.file: + path: /etc/sudoers + follow: false + group: '{{ file_groupowner_etc_sudoers_newgroup }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_groupowner_etc_sudoers @@ -11258,19 +12200,38 @@ ensures exclusive control of the sudo configuration. Verify User Who Owns /etc/sudoers File - To properly set the owner of /etc/sudoers, run the command: $ sudo chown root /etc/sudoers + To properly set the owner of /etc/sudoers, run the command: +$ sudo chown root /etc/sudoers R50 The ownership of the /etc/sudoers file by the root user is important because this file hosts sudo configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - chown 0 /etc/sudoers + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/sudoers" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/sudoers +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/sudoers - stat: - path: /etc/sudoers - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_owner_etc_sudoers @@ -11279,11 +12240,39 @@ ensures exclusive control of the sudo configuration. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/sudoers - file: +- name: Set the file_owner_etc_sudoers_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_sudoers_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sudoers + ansible.builtin.stat: path: /etc/sudoers - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /etc/sudoers + ansible.builtin.file: + path: /etc/sudoers + follow: false + owner: '{{ file_owner_etc_sudoers_newown }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_owner_etc_sudoers @@ -11308,16 +12297,31 @@ ensures exclusive control of the sudo configuration. because this file hosts sudo configuration. Protection of this file is critical for system security. Restricting the permissions ensures exclusive control of the sudo configuration. - - - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chmod u-xws,g-xws,o-xwrt /etc/sudoers + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/sudoers - stat: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sudoers + ansible.builtin.stat: path: /etc/sudoers register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_etc_sudoers @@ -11327,10 +12331,12 @@ chmod u-xws,g-xws,o-xwrt /etc/sudoers - no_reboot_needed - name: Ensure permission u-xws,g-xws,o-xwrt on /etc/sudoers - file: + ansible.builtin.file: path: /etc/sudoers mode: u-xws,g-xws,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_permissions_etc_sudoers @@ -11350,13 +12356,14 @@ chmod u-xws,g-xws,o-xwrt /etc/sudoers Ensure That the sudo Binary Has the Correct Permissions To properly set the permissions of /usr/bin/sudo, run the command: -$ sudo chmod 4111 /usr/bin/sudo - +$ sudo chmod 4110 /usr/bin/sudo +In order to use this rule, the group owner for /usr/bin/sudo needs to be changed to a +group other than root to effectively limit access to sudo. R38 The sudoers program should only be usable by people who have the correct permissions. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then chmod 4110 /usr/bin/sudo @@ -11376,10 +12383,12 @@ fi - no_reboot_needed - name: Test for existence /usr/bin/sudo - stat: + ansible.builtin.stat: path: /usr/bin/sudo register: file_exists - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - configure_strategy - file_permissions_sudo @@ -11389,10 +12398,11 @@ fi - no_reboot_needed - name: Ensure permission 4110 on /usr/bin/sudo - file: + ansible.builtin.file: path: /usr/bin/sudo mode: '4110' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists tags: @@ -11417,10 +12427,12 @@ in /etc/sudoers.d/. R39 Restricting the capability of sudo allowed commands to execute sub-commands prevents users from running programs with privileges they wouldn't have otherwise. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\bnoexec\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\bnoexec.*$' /etc/sudoers; then # sudoers file doesn't define Option noexec echo "Defaults noexec" >> /etc/sudoers fi @@ -11437,13 +12449,29 @@ else echo "Skipping remediation, /etc/sudoers failed to validate" false fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure noexec is enabled in /etc/sudoers - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sudo_add_noexec + +- name: Ensure noexec is enabled in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\bnoexec\b.*$ line: Defaults noexec validate: /usr/sbin/visudo -cf %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - high_severity - low_complexity @@ -11469,10 +12497,12 @@ in /etc/sudoers.d/. R39 Restricting the use cases in which a user is allowed to execute sudo commands reduces the attack surface. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\brequiretty\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\brequiretty.*$' /etc/sudoers; then # sudoers file doesn't define Option requiretty echo "Defaults requiretty" >> /etc/sudoers fi @@ -11489,13 +12519,29 @@ else echo "Skipping remediation, /etc/sudoers failed to validate" false fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure requiretty is enabled in /etc/sudoers - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_add_requiretty + +- name: Ensure requiretty is enabled in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\brequiretty\b.*$ line: Defaults requiretty validate: /usr/sbin/visudo -cf %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity - low_disruption @@ -11527,11 +12573,11 @@ in /etc/sudoers.d/. access to the user's terminal after the main program has finished executing. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\buse_pty\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\buse_pty.*$' /etc/sudoers; then # sudoers file doesn't define Option use_pty echo "Defaults use_pty" >> /etc/sudoers fi @@ -11568,12 +12614,14 @@ fi - sudo_add_use_pty - name: Ensure use_pty is enabled in /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\buse_pty\b.*$ line: Defaults use_pty validate: /usr/sbin/visudo -cf %s - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - PCI-DSS-Req-10.2.5 - PCI-DSSv4-2.2 @@ -11603,14 +12651,14 @@ a sudo custom logfile at the default location suggested by CIS, which uses A sudo log file simplifies auditing of sudo commands. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then var_sudo_logfile='' if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\blogfile\s*=\s*(?:"?([^",\s]+)"?)\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$' /etc/sudoers; then # sudoers file doesn't define Option logfile echo "Defaults logfile=${var_sudo_logfile}" >> /etc/sudoers else @@ -11659,14 +12707,16 @@ fi - always - name: Ensure logfile is enabled with the appropriate value in /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults\s(.*)\blogfile=[-]?.+\b(.*)$ line: Defaults \1logfile={{ var_sudo_logfile }}\2 validate: /usr/sbin/visudo -cf %s backrefs: true register: edit_sudoers_logfile_option - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - PCI-DSS-Req-10.2.5 - PCI-DSSv4-2.2 @@ -11679,11 +12729,12 @@ fi - sudo_custom_logfile - name: Enable logfile option with appropriate value in /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers line: Defaults logfile={{ var_sudo_logfile }} validate: /usr/sbin/visudo -cf %s when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - edit_sudoers_logfile_option is defined and not edit_sudoers_logfile_option.changed tags: @@ -11738,7 +12789,6 @@ any sudo configuration snippets in /etc/sudoers.d/.DSS05.10 DSS06.03 DSS06.10 - CCI-004895 4.3.3.5.1 4.3.3.6.1 4.3.3.6.2 @@ -11771,18 +12821,21 @@ any sudo configuration snippets in /etc/sudoers.d/.CM-6(a) PR.AC-1 PR.AC-7 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - OL09-00-002362 - SV-271724r1091884_rule + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + 1546 + OL09-00-002362 + SV-271724r1091884_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -11797,12 +12850,31 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ files + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002362 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-11 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_remove_no_authenticate + +- name: Find /etc/sudoers.d/ files ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002362 - NIST-800-53-CM-6(a) @@ -11823,6 +12895,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002362 - NIST-800-53-CM-6(a) @@ -11857,7 +12930,6 @@ in /etc/sudoers.d/. DSS05.10 DSS06.03 DSS06.10 - CCI-004895 4.3.3.5.1 4.3.3.6.1 4.3.3.6.2 @@ -11890,18 +12962,21 @@ in /etc/sudoers.d/. CM-6(a) PR.AC-1 PR.AC-7 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - OL09-00-002363 - SV-271725r1091887_rule + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + 1546 + OL09-00-002363 + SV-271725r1091887_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -11916,12 +12991,31 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ files + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002363 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-11 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_remove_nopasswd + +- name: Find /etc/sudoers.d/ files ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002363 - NIST-800-53-CM-6(a) @@ -11942,6 +13036,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002363 - NIST-800-53-CM-6(a) @@ -11977,8 +13072,6 @@ in /etc/sudoers.d/." DSS05.10 DSS06.03 DSS06.10 - CCI-002038 - CCI-004895 4.3.3.5.1 4.3.3.6.1 4.3.3.6.2 @@ -12011,8 +13104,9 @@ in /etc/sudoers.d/." CM-6(a) PR.AC-1 PR.AC-7 - SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00156 A.5.SEC-OL2 + 1546 2.2.6 2.2 Without re-authentication, users may access resources or perform tasks for which they @@ -12021,7 +13115,9 @@ do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -12051,12 +13147,32 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ files + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_require_authentication + +- name: Find /etc/sudoers.d/ files ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12078,6 +13194,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12095,6 +13212,7 @@ done paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12116,6 +13234,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12145,16 +13264,15 @@ The timestamp_timeout should be configured by making sure that the in /etc/sudoers.d/. If the value is set to an integer less than 0, the user's time stamp will not expire and the user will not have to re-authenticate for privileged actions until the user's session is terminated. - CCI-004895 IA-11 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 A.5.SEC-OL2 2.2.6 2.2 - OL09-00-002360 - SV-271722r1091878_rule + OL09-00-002360 + SV-271722r1091878_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. @@ -12163,7 +13281,7 @@ When operating systems provide the capability to escalate a functional capabilit is critical that the user re-authenticate. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then var_sudo_timestamp_timeout='' @@ -12228,7 +13346,9 @@ fi patterns: '*' contains: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.* register: sudoers_d_defaults_timestamp_timeout - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12248,7 +13368,9 @@ fi regexp: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.* state: absent with_items: '{{ sudoers_d_defaults_timestamp_timeout.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12270,7 +13392,9 @@ fi validate: /usr/sbin/visudo -cf %s backrefs: true register: edit_sudoers_timestamp_timeout_option - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12290,6 +13414,7 @@ fi line: Defaults timestamp_timeout={{ var_sudo_timestamp_timeout }} validate: /usr/sbin/visudo -cf %s when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - | edit_sudoers_timestamp_timeout_option is defined and not edit_sudoers_timestamp_timeout_option.changed @@ -12313,7 +13438,9 @@ fi }}\b)[-]?\w+\b.*$ state: absent validate: /usr/sbin/visudo -cf %s - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12345,12 +13472,11 @@ Restrict privileged actions by removing the following entries from the sudoers f This rule doesn't come with a remediation, as the exact requirement allows exceptions, and removing lines from the sudoers file can make the system non-administrable. - CCI-000366 CM-6(b) CM-6(iv) - SRG-OS-000480-GPOS-00227 - OL09-00-000232 - SV-271476r1091140_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000232 + SV-271476r1091140_rule If the "sudoers" file is not configured correctly, any user defined on the system can initiate privileged actions on the target system. @@ -12461,17 +13587,16 @@ or if cvtsudoers not supported: /etc/sudoers:Defaults !rootpw /etc/sudoers:Defaults !runaspw - CCI-000366 CM-6(b) CM-6.1(iv) - SRG-OS-000480-GPOS-00227 - OL09-00-000231 - SV-271475r1091137_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000231 + SV-271475r1091137_rule If the rootpw, targetpw, or runaspw flags are defined and not disabled, by default the operating system will prompt the invoking user for the "root" user password. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then if grep -x '^Defaults targetpw$' /etc/sudoers; then sed -i "/Defaults targetpw/d" /etc/sudoers \; @@ -12554,12 +13679,14 @@ fi - sudoers_validate_passwd - name: Find out if /etc/sudoers.d/* files contain Defaults targetpw to be deduplicated - find: + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^Defaults targetpw$ register: sudoers_d_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12572,12 +13699,14 @@ fi - sudoers_validate_passwd - name: Remove found occurrences of Defaults targetpw from /etc/sudoers.d/* files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^Defaults targetpw$ state: absent with_items: '{{ sudoers_d_defaults.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12590,12 +13719,14 @@ fi - sudoers_validate_passwd - name: Find out if /etc/sudoers.d/* files contain Defaults rootpw to be deduplicated - find: + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^Defaults rootpw$ register: sudoers_d_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12608,12 +13739,14 @@ fi - sudoers_validate_passwd - name: Remove found occurrences of Defaults rootpw from /etc/sudoers.d/* files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^Defaults rootpw$ state: absent with_items: '{{ sudoers_d_defaults.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12626,12 +13759,14 @@ fi - sudoers_validate_passwd - name: Find out if /etc/sudoers.d/* files contain Defaults runaspw to be deduplicated - find: + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^Defaults runaspw$ register: sudoers_d_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12644,12 +13779,14 @@ fi - sudoers_validate_passwd - name: Remove found occurrences of Defaults runaspw from /etc/sudoers.d/* files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^Defaults runaspw$ state: absent with_items: '{{ sudoers_d_defaults.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12661,14 +13798,16 @@ fi - restrict_strategy - sudoers_validate_passwd -- name: Remove any ocurrences of Defaults targetpw in /etc/sudoers - lineinfile: +- name: Remove any occurrences of Defaults targetpw in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^Defaults targetpw$ validate: /usr/sbin/visudo -cf %s state: absent register: sudoers_file_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12680,14 +13819,16 @@ fi - restrict_strategy - sudoers_validate_passwd -- name: Remove any ocurrences of Defaults rootpw in /etc/sudoers - lineinfile: +- name: Remove any occurrences of Defaults rootpw in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^Defaults rootpw$ validate: /usr/sbin/visudo -cf %s state: absent register: sudoers_file_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12699,14 +13840,16 @@ fi - restrict_strategy - sudoers_validate_passwd -- name: Remove any ocurrences of Defaults runaspw in /etc/sudoers - lineinfile: +- name: Remove any occurrences of Defaults runaspw in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^Defaults runaspw$ validate: /usr/sbin/visudo -cf %s state: absent register: sudoers_file_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12719,7 +13862,7 @@ fi - sudoers_validate_passwd - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !targetpw$ @@ -12727,7 +13870,9 @@ fi check_mode: true changed_when: false register: dupes - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12740,12 +13885,13 @@ fi - sudoers_validate_passwd - name: Deduplicate values from /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !targetpw$ state: absent when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: @@ -12760,13 +13906,15 @@ fi - sudoers_validate_passwd - name: Insert correct line into /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !targetpw$ line: Defaults !targetpw state: present - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12779,7 +13927,7 @@ fi - sudoers_validate_passwd - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !rootpw$ @@ -12787,7 +13935,9 @@ fi check_mode: true changed_when: false register: dupes - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12800,12 +13950,13 @@ fi - sudoers_validate_passwd - name: Deduplicate values from /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !rootpw$ state: absent when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: @@ -12820,13 +13971,15 @@ fi - sudoers_validate_passwd - name: Insert correct line into /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !rootpw$ line: Defaults !rootpw state: present - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12839,7 +13992,7 @@ fi - sudoers_validate_passwd - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !runaspw$ @@ -12847,7 +14000,9 @@ fi check_mode: true changed_when: false register: dupes - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12860,12 +14015,13 @@ fi - sudoers_validate_passwd - name: Deduplicate values from /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !runaspw$ state: absent when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: @@ -12880,13 +14036,15 @@ fi - sudoers_validate_passwd - name: Insert correct line into /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !runaspw$ line: Defaults !runaspw state: present - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12926,15 +14084,37 @@ provide secure management of multiple user passwords. In contrast to existing so LUKS stores all necessary setup information in the partition header, enabling the user to transport or migrate their data seamlessly. LUKS for dm-crypt is implemented in cryptsetup. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if ! rpm -q --quiet "cryptsetup" ; then yum install -y "cryptsetup" fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure cryptsetup is installed - package: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-3.5 + - PCI-DSSv4-3.5.1 + - PCI-DSSv4-3.5.1.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_cryptsetup-luks_installed + +- name: Ensure cryptsetup is installed + ansible.builtin.package: name: cryptsetup state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-3.5 - PCI-DSSv4-3.5.1 @@ -12975,13 +14155,12 @@ version = "*" $ sudo yum install gnutls-utils - CCI-000366 FIA_X509_EXT.1 FIA_X509_EXT.1.1 FIA_X509_EXT.2 - SRG-OS-000480-GPOS-00227 - OL09-00-000430 - SV-271518r1091266_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000430 + SV-271518r1091266_rule GnuTLS is a secure communications library implementing the SSL, TLS and DTLS protocols and technologies around them. It provides a simple C language application programming interface (API) to access the secure communications @@ -12995,7 +14174,7 @@ if ! rpm -q --quiet "gnutls-utils" ; then fi - name: Ensure gnutls-utils is installed - package: + ansible.builtin.package: name: gnutls-utils state: present tags: @@ -13036,11 +14215,10 @@ version = "*" $ sudo yum install nss-tools - CCI-000366 FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-000380 - SV-271513r1091251_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000380 + SV-271513r1091251_rule Network Security Services (NSS) is a set of libraries designed to support cross-platform development of security-enabled client and server applications. Install the nss-tools package @@ -13052,7 +14230,7 @@ if ! rpm -q --quiet "nss-tools" ; then fi - name: Ensure nss-tools is installed - package: + ansible.builtin.package: name: nss-tools state: present tags: @@ -13095,8 +14273,8 @@ $ sudo yum install openscap-scanner AGD_PRE.1 AGD_OPE.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000191-GPOS-00080 + SRG-OS-000480-GPOS-00227 + SRG-OS-000191-GPOS-00080 openscap-scanner contains the oscap command line tool. This tool is a configuration and vulnerability scanner, capable of performing compliance checking using SCAP content. @@ -13106,7 +14284,7 @@ if ! rpm -q --quiet "openscap-scanner" ; then fi - name: Ensure openscap-scanner is installed - package: + ansible.builtin.package: name: openscap-scanner state: present tags: @@ -13146,6 +14324,7 @@ version = "*" $ sudo yum install rear + 1409 rear contains the Relax-and-Recover (ReaR) utility. ReaR produces a bootable image of a system and restores from backup using this image. @@ -13161,7 +14340,7 @@ else fi - name: Ensure rear is installed - package: + ansible.builtin.package: name: rear state: present when: not ( ( ( ansible_architecture == "aarch64" and ansible_distribution == 'OracleLinux' @@ -13206,10 +14385,9 @@ version = "*" $ sudo yum install rng-tools - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-000370 - SV-271512r1091248_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000370 + SV-271512r1091248_rule rng-tools provides hardware random number generator tools, such as those used in the formation of x509/PKI certificates. @@ -13237,7 +14415,7 @@ fi - package_rng-tools_installed - name: Ensure rng-tools is installed - package: + ansible.builtin.package: name: rng-tools state: present when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -13282,7 +14460,7 @@ $ sudo yum install scap-security-guide AGD_PRE.1 AGD_OPE.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 The scap-security-guide package provides a guide for configuration of the system from the final system's security point of view. The guidance is specified in the Security Content Automation Protocol (SCAP) format and constitutes a catalog of practical hardening @@ -13291,14 +14469,14 @@ bridges the gap between generalized policy requirements and specific implementat A system administrator can use the oscap CLI tool from the openscap-scanner package, or the SCAP Workbench GUI tool from the scap-workbench package, to verify that the system conforms to provided guidelines. Refer to the scap-security-guide(8) manual -page for futher information. +page for further information. if ! rpm -q --quiet "scap-security-guide" ; then yum install -y "scap-security-guide" fi - name: Ensure scap-security-guide is installed - package: + ansible.builtin.package: name: scap-security-guide state: present tags: @@ -13338,28 +14516,27 @@ version = "*" $ sudo yum erase gssproxy - CCI-000366 - CCI-000381 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000115 - SV-271459r1091089_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000115 + SV-271459r1091089_rule gssproxy is a proxy for GSS API credential handling. Kerberos relies on some key derivation functions that may not be compatible with some site policies such as FIPS 140. # CAUTION: This remediation script will remove gssproxy -# from the system, and may remove any packages -# that depend on gssproxy. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on gssproxy. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "gssproxy" ; then yum remove -y "gssproxy" fi - - name: Ensure gssproxy is removed - package: + - name: 'Uninstall gssproxy Package: Ensure gssproxy is removed' + ansible.builtin.package: name: gssproxy state: absent tags: @@ -13371,7 +14548,8 @@ fi - no_reboot_needed - package_gssproxy_removed - include remove_gssproxy + +include remove_gssproxy class remove_gssproxy { package { 'gssproxy': @@ -13392,27 +14570,26 @@ class remove_gssproxy { $ sudo yum erase iprutils - CCI-000366 - CCI-000381 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000120 - SV-271460r1091092_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000120 + SV-271460r1091092_rule iprutils provides a suite of utlilities to manage and configure SCSI devices supported by the ipr SCSI storage device driver. # CAUTION: This remediation script will remove iprutils -# from the system, and may remove any packages -# that depend on iprutils. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on iprutils. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "iprutils" ; then yum remove -y "iprutils" fi - - name: Ensure iprutils is removed - package: + - name: 'Uninstall iprutils Package: Ensure iprutils is removed' + ansible.builtin.package: name: iprutils state: absent tags: @@ -13424,7 +14601,8 @@ fi - no_reboot_needed - package_iprutils_removed - include remove_iprutils + +include remove_iprutils class remove_iprutils { package { 'iprutils': @@ -13433,6 +14611,7 @@ class remove_iprutils { } + package --remove=iprutils @@ -13448,29 +14627,28 @@ package --remove=iprutils $ sudo yum erase tuned - CCI-000366 - CCI-000381 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000125 - SV-271461r1091095_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000125 + SV-271461r1091095_rule tuned contains a daemon that tunes the system settings dynamically. It does so by monitoring the usage of several system components periodically. Based on that information, components will then be put into lower or higher power savings modes to adapt to the current usage. # CAUTION: This remediation script will remove tuned -# from the system, and may remove any packages -# that depend on tuned. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on tuned. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "tuned" ; then yum remove -y "tuned" fi - - name: Ensure tuned is removed - package: + - name: 'Uninstall tuned Package: Ensure tuned is removed' + ansible.builtin.package: name: tuned state: absent tags: @@ -13482,7 +14660,8 @@ fi - no_reboot_needed - package_tuned_removed - include remove_tuned + +include remove_tuned class remove_tuned { package { 'tuned': @@ -13491,6 +14670,7 @@ class remove_tuned { } + package --remove=tuned @@ -13524,13 +14704,13 @@ $ sudo yum install dnf-automatic FPT_TUD_EXT.1 FPT_TUD_EXT.2 - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 R61 dnf-automatic is an alternative command line interface (CLI) to dnf upgrade suitable for automatic, regular execution. - + # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then if ! rpm -q --quiet "dnf-automatic" ; then yum install -y "dnf-automatic" @@ -13552,12 +14732,13 @@ fi - package_dnf-automatic_installed - name: Ensure dnf-automatic is installed - package: + ansible.builtin.package: name: dnf-automatic state: present - when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - enable_strategy - low_complexity @@ -13609,7 +14790,6 @@ to 1 in /etc/yum.conf.DSS05.01 DSS05.02 3.4.8 - CCI-002617 4.2.3 4.2.3.12 4.2.3.7 @@ -13625,14 +14805,14 @@ to 1 in /etc/yum.conf.CM-6(a) ID.RA-1 PR.IP-12 - SRG-OS-000437-GPOS-00194 - OL09-00-000495 - SV-271522r1091278_rule + SRG-OS-000437-GPOS-00194 + OL09-00-000495 + SV-271522r1091278_rule Previous versions of software components that are not removed from the information system after updates have been installed may be exploited by some adversaries. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q yum; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && rpm --quiet -q yum ); then if grep --silent ^clean_requirements_on_remove /etc/yum.conf ; then sed -i "s/^clean_requirements_on_remove.*/clean_requirements_on_remove=1/g" /etc/yum.conf @@ -13670,7 +14850,9 @@ fi line: clean_requirements_on_remove=1 insertafter: \[main\] create: true - when: '"yum" in ansible_facts.packages' + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) and "yum" in ansible_facts.packages ) tags: - DISA-STIG-OL09-00-000495 - NIST-800-171-3.4.8 @@ -13695,20 +14877,15 @@ fi Configure dnf-automatic to Install Available Updates Automatically To ensure that the packages comprising the available updates will be automatically installed by dnf-automatic, set apply_updates to yes under [commands] section in /etc/dnf/automatic.conf. - 0940 - 1144 - 1467 - 1472 - 1483 - 1493 - 1494 - 1495 SI-2(5) CM-6(a) SI-2(c) FMT_SMF_EXT.1 - SRG-OS-000805-GPOS-00260 + SRG-OS-000805-GPOS-00260 R61 + 1467 + 1483 + 1493 Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized @@ -13716,9 +14893,9 @@ users may take advantage of weaknesses in the unpatched software. The lack of prompt attention to patching could result in a system compromise. The automated installation of updates ensures that recent security patches are applied in a timely manner. - + # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then found=false @@ -13730,10 +14907,13 @@ for f in $(echo -n "/etc/dnf/automatic.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[commands\]([^\n\[]*\n+)+?[[:space:]]*apply_updates" "$f"; then + if ! grep -qPz "apply_updates=yes" "$f"; then sed -i "s/apply_updates[^(\n)]*/apply_updates=yes/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[commands\]" "$f"; then @@ -13772,14 +14952,15 @@ automatically, set upgrade_type to securitySI-2(5) CM-6(a) SI-2(c) - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 R61 + 1493 By default, dnf-automatic installs all available updates. Reducing the amount of updated packages only to updates that were issued as a part of a security advisory increases the system stability. - + # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then found=false @@ -13791,10 +14972,13 @@ for f in $(echo -n "/etc/dnf/automatic.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[commands\]([^\n\[]*\n+)+?[[:space:]]*upgrade_type" "$f"; then + if ! grep -qPz "upgrade_type=security" "$f"; then sed -i "s/upgrade_type[^(\n)]*/upgrade_type=security/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[commands\]" "$f"; then @@ -13825,6 +15009,155 @@ fi + + Ensure EPEL Repository is Disabled + The system must not have the EPEL (Extra Packages for Enterprise Linux) repository enabled. +EPEL provides additional packages that are not part of the official RHEL distribution and +may not meet enterprise security requirements. + +Check if any repository files in /etc/yum.repos.d/ contain enabled EPEL repositories +by running: +$ grep -r "^\[.*epel.*\]" /etc/yum.repos.d/ + +If EPEL repositories are found, ensure they are disabled by setting enabled=0 in +the repository configuration file. + CCI-000381 + SRG-OS-000095-GPOS-00049 + OL09-00-000105 + SV-271457r1134853_rule + The EPEL repository is not officially supported by Red Hat and may contain packages that have +not been vetted for security in an enterprise environment. Using unsupported repositories can +introduce vulnerabilities, compatibility issues, or packages that do not meet DoD security +requirements. Only packages from authorized repositories should be installed to maintain +system integrity and security. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q yum; then + +# Ensure dnf-plugins-core is available for dnf config-manager +if ! command -v dnf &> /dev/null; then + # System uses yum instead of dnf + if command -v yum-config-manager &> /dev/null; then + CONFIG_MANAGER="yum-config-manager" + else + echo "Neither dnf nor yum-config-manager found, cannot disable repositories" >&2 + exit 1 + fi +else + # System uses dnf + if ! command -v dnf config-manager &> /dev/null 2>&1; then + dnf install -y dnf-plugins-core + fi + CONFIG_MANAGER="dnf config-manager" +fi + +# Find all EPEL repository IDs by name pattern +for repo_file in /etc/yum.repos.d/*.repo; do + [ -f "$repo_file" ] || continue + + # Extract repository IDs that contain "epel" (case-insensitive) + while IFS= read -r repo_id; do + $CONFIG_MANAGER --set-disabled "$repo_id" + done < <(grep -ioP '^\[\K[^\]]*epel[^\]]*(?=\])' "$repo_file") +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure dnf-plugins-core is installed + package: + name: dnf-plugins-core + state: present + when: + - '"yum" in ansible_facts.packages' + - ansible_pkg_mgr == "dnf" + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find all repository files + find: + paths: /etc/yum.repos.d/ + patterns: '*.repo' + register: repo_files + when: '"yum" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find EPEL repository IDs by name + shell: | + set -o pipefail + # Find repository IDs by name (case-insensitive) + grep -ioP '^\[\K[^\]]*epel[^\]]*(?=\])' "{{ item.path }}" || true + register: epel_repo_ids + loop: '{{ repo_files.files }}' + changed_when: false + when: + - '"yum" in ansible_facts.packages' + - repo_files.files is defined + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Disable EPEL repositories using dnf/yum config-manager + command: '{% if ansible_pkg_mgr == "dnf" %} dnf config-manager --set-disabled {{ + item.1 }} {% else %} yum-config-manager --set-disabled {{ item.1 }} {% endif %}' + loop: '{{ epel_repo_ids.results | subelements(''stdout_lines'', skip_missing=True) + }}' + when: + - '"yum" in ansible_facts.packages' + - epel_repo_ids.results is defined + - item.1 | length > 0 + loop_control: + label: '{{ item.1 }}' + register: disable_result + changed_when: disable_result.rc == 0 + failed_when: false + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + Ensure gpgcheck Enabled In Main yum Configuration The gpgcheck option controls whether @@ -13848,7 +15181,6 @@ the [main] section: BAI10.05 DSS06.02 3.4.8 - CCI-003992 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -13887,12 +15219,13 @@ the [main] section: FPT_TUD_EXT.1 FPT_TUD_EXT.2 Req-6.2 - SRG-OS-000366-GPOS-00153 + SRG-OS-000366-GPOS-00153 R59 + 1493 6.3.3 6.3 - OL09-00-000497 - SV-271524r1091284_rule + OL09-00-000497 + SV-271524r1091284_rule Changes to any software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided by a @@ -13962,7 +15295,7 @@ fi - no_reboot_needed - name: Ensure GPG check is globally activated - ini_file: + community.general.ini_file: dest: /etc/yum.conf section: main option: gpgcheck @@ -14013,7 +15346,6 @@ packages, set the localpkg_gpgcheck to 1BAI10.03 BAI10.05 3.4.8 - CCI-003992 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -14037,10 +15369,11 @@ packages, set the localpkg_gpgcheck to 1PR.IP-1 FPT_TUD_EXT.1 FPT_TUD_EXT.2 - SRG-OS-000366-GPOS-00153 + SRG-OS-000366-GPOS-00153 R59 - OL09-00-000496 - SV-271523r1091281_rule + 1493 + OL09-00-000496 + SV-271523r1091281_rule Changes to any software components can have significant effects to the overall security of the operating system. This requirement ensures the software has not been tampered and has been provided by a trusted vendor. @@ -14099,7 +15432,7 @@ fi block: - name: Check stats of yum - stat: + ansible.builtin.stat: path: /etc/yum.conf register: pkg @@ -14110,7 +15443,7 @@ fi when: pkg.stat.lnk_target is defined - name: Ensure GPG check Enabled for Local Packages (yum) - ini_file: + community.general.ini_file: dest: '{{ pkg_config_file_symlink | default("/etc/yum.conf") }}' section: main option: localpkg_gpgcheck @@ -14161,7 +15494,6 @@ any repos, remove any lines from files in /etc/yum.repos.dBAI10.05 DSS06.02 3.4.8 - CCI-003992 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -14200,12 +15532,13 @@ any repos, remove any lines from files in /etc/yum.repos.dFPT_TUD_EXT.1 FPT_TUD_EXT.2 Req-6.2 - SRG-OS-000366-GPOS-00153 + SRG-OS-000366-GPOS-00153 R59 + 1493 6.3.3 6.3 - OL09-00-000498 - SV-271525r1091287_rule + OL09-00-000498 + SV-271525r1091287_rule Verifying the authenticity of the software prior to installation validates the integrity of the patch or upgrade received from a vendor. This ensures the software has not been tampered with and that it has been provided by a @@ -14216,7 +15549,7 @@ approved Certificate Authority (CA)." sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - name: Grep for yum repo section names - shell: | + ansible.builtin.shell: | set -o pipefail grep -HEr '^\[.+\]' -r /etc/yum.repos.d/ register: repo_grep_results @@ -14246,7 +15579,7 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - no_reboot_needed - name: Set gpgcheck=1 for each yum repo - ini_file: + community.general.ini_file: path: '{{ item[0] }}' section: '{{ item[1] }}' option: gpgcheck @@ -14315,7 +15648,6 @@ such cases, the key can be installed by running the following command: BAI10.03 BAI10.05 DSS06.02 - CCI-001749 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -14346,8 +15678,8 @@ such cases, the key can be installed by running the following command: PR.IP-1 Req-6.2 R59 - OL09-00-000499 - SV-271526r1092460_rule + OL09-00-000499 + SV-271526r1092460_rule Changes to software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided @@ -14536,7 +15868,6 @@ dictates. BAI03.10 DSS05.01 DSS05.02 - CCI-000366 4.2.3 4.2.3.12 4.2.3.7 @@ -14553,12 +15884,13 @@ dictates. PR.IP-12 FMT_MOF_EXT.1 Req-6.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R61 + 1409 6.3.3 6.3 - OL09-00-000015 - SV-271439r1091029_rule + OL09-00-000015 + SV-271439r1091029_rule Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized @@ -14569,7 +15901,7 @@ lack of prompt attention to patching could result in a system compromise. - name: Security patches are up to date - package: + ansible.builtin.package: name: '*' state: latest tags: @@ -14603,13 +15935,13 @@ The dnf-automatic timer can be enabled with the following CM-6(a) SI-2(c) FMT_SMF_EXT.1 - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 R61 The dnf-automatic is an alternative command line interface (CLI) to dnf upgrade with specific facilities to make it suitable to be executed automatically and regularly from systemd timers, cron jobs and similar. The tool is controlled by dnf-automatic.timer SystemD timer. - + # Remediation is applicable only in certain platforms -if ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then SYSTEMCTL_EXEC='/usr/bin/systemctl' if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then @@ -14639,19 +15971,20 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable timer dnf-automatic - systemd: + ansible.builtin.systemd: name: dnf-automatic.timer enabled: 'yes' state: started when: - '"dnf-automatic" in ansible_facts.packages' - when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(a) - NIST-800-53-SI-2(5) @@ -14663,6 +15996,10 @@ fi - no_reboot_needed - timer_dnf-automatic_enabled + + + + @@ -14685,6 +16022,7 @@ Oracle Linux 9. Authselect profile Specify the authselect profile to select + local minimal minimal sssd @@ -14698,7 +16036,6 @@ profile cannot be selected, it is probably because PAM files have already been m the administrator. If this is the case, in order to not overwrite the desired changes made by the administrator, the current PAM settings should be investigated before forcing the selection of the chosen authselect profile. - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -14713,26 +16050,34 @@ selection of the chosen authselect profile. AC-3 FIA_UAU.1 FIA_AFL.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R31 enable_authselect + 1409 8.3.4 8.3 - needed_rules + needed_rules Authselect is a successor to authconfig. It is a tool to select system authentication and identity sources from a list of supported profiles instead of letting the administrator manually build the PAM stack. That way, it avoids potential breakage of configuration, as it ships several tested profiles that are well tested and supported to solve different use-cases. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_authselect_profile='' authselect current if test "$?" -ne 0; then - authselect select "$var_authselect_profile" + if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then + authselect select --force "$var_authselect_profile" + else + authselect select "$var_authselect_profile" + fi if test "$?" -ne 0; then if rpm --quiet --verify pam; then @@ -14742,8 +16087,26 @@ if test "$?" -ne 0; then fi fi fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_authselect_profile # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-needed_rules + - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 + - configure_strategy + - enable_authselect + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_authselect_profile # promote to variable set_fact: var_authselect_profile: !!str tags: @@ -14755,6 +16118,7 @@ fi register: result_authselect_current changed_when: false failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-needed_rules - NIST-800-53-AC-3 @@ -14773,7 +16137,9 @@ fi register: result_authselect_select changed_when: result_authselect_select.rc == 0 failed_when: false - when: result_authselect_current.rc != 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_current.rc != 0 tags: - DISA-STIG-needed_rules - NIST-800-53-AC-3 @@ -14793,6 +16159,7 @@ fi changed_when: false failed_when: false when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_authselect_select is not skipped - result_authselect_select.rc != 0 tags: @@ -14815,6 +16182,7 @@ fi fail_msg: - authselect is not used but files from the 'pam' package have been altered, so the authselect configuration won't be forced. + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-needed_rules - NIST-800-53-AC-3 @@ -14831,6 +16199,7 @@ fi ansible.builtin.command: cmd: authselect select --force "{{ var_authselect_profile }}" when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_authselect_current.rc != 0 - result_authselect_select.rc != 0 - result_altered_authselect.rc == 0 @@ -14958,12 +16327,6 @@ OR: DSS05.10 DSS06.10 3.1.9 - CCI-001387 - CCI-001384 - CCI-000048 - CCI-001386 - CCI-001388 - CCI-001385 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -14989,11 +16352,11 @@ OR: AC-8(a) AC-8(c) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 - OL09-00-000090 - SV-271455r1091077_rule + OL09-00-000090 + SV-271455r1091077_rule Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, @@ -15009,7 +16372,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then login_banner_text='' - # Multiple regexes transform the banner regex into a usable banner # 0 - Remove anchors around the banner text login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g') @@ -15020,7 +16382,7 @@ login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g') login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n") login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g') formatted=$(echo "$login_banner_text" | fold -sw 80) cat <<EOF >/etc/issue @@ -15052,7 +16414,7 @@ fi - always - name: Modify the System Login Banner - Ensure Correct Banner - copy: + ansible.builtin.copy: dest: /etc/issue content: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", @@ -15114,14 +16476,8 @@ OR: I've read & consent to terms in IS user agreem't. - CCI-000048 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification @@ -15149,7 +16505,7 @@ remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/^(\(.*\.\)| remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n") remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/\\//g') formatted=$(echo "$remote_login_banner_text" | fold -sw 80) @@ -15178,7 +16534,7 @@ fi - always - name: Modify the System Login Banner for Remote Connections - ensure correct banner - copy: + ansible.builtin.copy: dest: /etc/issue.net content: '{{ remote_login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", @@ -15263,7 +16619,7 @@ motd_banner_text=$(echo "$motd_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g') motd_banner_text=$(echo "$motd_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n") motd_banner_text=$(echo "$motd_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). motd_banner_text=$(echo "$motd_banner_text" | sed 's/\\//g') formatted=$(echo "$motd_banner_text" | fold -sw 80) @@ -15292,7 +16648,7 @@ fi - always - name: Modify the System Message of the Day Banner - ensure correct banner - copy: + ansible.builtin.copy: dest: /etc/motd content: '{{ motd_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", @@ -15318,7 +16674,8 @@ fi Verify Group Ownership of System Login Banner for Remote Connections To properly set the group owner of /etc/issue.net, run the command: -$ sudo chgrp root /etc/issue.net + + $ sudo chgrp root /etc/issue.net 1.2.8 1.2 @@ -15327,10 +16684,37 @@ access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. Proper group ownership will ensure that only root user can modify the banner. - chgrp 0 /etc/issue.net + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/issue.net" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/issue.net +fi + +fi - - name: Test for existence /etc/issue.net - stat: + - name: Set the file_groupowner_etc_issue_net_newgroup variable if represented by + gid + ansible.builtin.set_fact: + file_groupowner_etc_issue_net_newgroup: '0' + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_groupowner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/issue.net + ansible.builtin.stat: path: /etc/issue.net register: file_exists tags: @@ -15343,10 +16727,11 @@ Proper group ownership will ensure that only root user can modify the banner.Verify ownership of System Login Banner for Remote Connections To properly set the owner of /etc/issue.net, run the command: -$ sudo chown root /etc/issue.net + + $ sudo chown root /etc/issue.net 1.2.8 1.2 @@ -15378,10 +16764,36 @@ access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. Proper ownership will ensure that only root user can modify the banner. - chown 0 /etc/issue.net + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/issue.net" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/issue.net +fi + +fi - - name: Test for existence /etc/issue.net - stat: + - name: Set the file_owner_etc_issue_net_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_issue_net_newown: '0' + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_owner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/issue.net + ansible.builtin.stat: path: /etc/issue.net register: file_exists tags: @@ -15394,10 +16806,11 @@ Proper ownership will ensure that only root user can modify the banner. - name: Test for existence /etc/issue.net - stat: + ansible.builtin.stat: path: /etc/issue.net register: file_exists tags: @@ -15450,7 +16863,7 @@ chmod u-xs,g-xws,o-xwt /etc/issue.net - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/issue.net - file: + ansible.builtin.file: path: /etc/issue.net mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -15505,12 +16918,6 @@ The banner text must also be set. DSS05.10 DSS06.10 3.1.9 - CCI-001387 - CCI-001384 - CCI-000048 - CCI-001386 - CCI-001388 - CCI-001385 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -15537,13 +16944,13 @@ The banner text must also be set. AC-8(b) AC-8(c) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 - OL09-00-002150 - OL09-00-002122 - SV-271688r1091776_rule - SV-271680r1091752_rule + OL09-00-002150 + OL09-00-002122 + SV-271688r1091776_rule + SV-271680r1091752_rule Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. @@ -15629,13 +17036,14 @@ fi - unknown_strategy - name: Enable GNOME3 Login Warning Banner - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: banner-message-enable value: 'true' create: true no_extra_spaces: true + register: result_ini when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002122 @@ -15652,11 +17060,12 @@ fi - unknown_strategy - name: Prevent user modification of GNOME banner-message-enabled - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/banner-message-enable$ line: /org/gnome/login-screen/banner-message-enable create: true + register: result_lineinfile when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002122 @@ -15673,8 +17082,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update - when: '"gdm" in ansible_facts.packages' + ansible.builtin.command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002122 - DISA-STIG-OL09-00-002150 @@ -15725,12 +17136,6 @@ to begin and end the string with ' and use \n< DSS05.10 DSS06.10 3.1.9 - CCI-000048 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -15756,11 +17161,11 @@ to begin and end the string with ' and use \n< AC-8(a) AC-8(c) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 - OL09-00-002151 - SV-271689r1091779_rule + OL09-00-002151 + SV-271689r1091779_rule An appropriate warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. # Remediation is applicable only in certain platforms @@ -15768,7 +17173,6 @@ if rpm --quiet -q gdm; then login_banner_text='' - # Multiple regexes transform the banner regex into a usable banner # 0 - Remove anchors around the banner text login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g') @@ -15779,7 +17183,7 @@ login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g') login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newline "tokens". (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "(n)*") login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/(n)*/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g') # 5 - Removes the newline "token." (Transforms them into newline escape sequences "\n"). # ( Needs to be done after 4, otherwise the escapce sequence will become just "n". @@ -15863,7 +17267,7 @@ fi - always - name: Set the GNOME3 Login Warning Banner Text - file: + ansible.builtin.file: path: /etc/dconf/db/{{ item }} owner: root group: root @@ -15886,7 +17290,7 @@ fi - unknown_strategy - name: Set the GNOME3 Login Warning Banner Text - file: + ansible.builtin.file: path: /etc/dconf/db/local.d/{{ item }} owner: root group: root @@ -15909,7 +17313,7 @@ fi - unknown_strategy - name: Set the GNOME3 Login Warning Banner Text - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: banner-message-text @@ -15918,6 +17322,7 @@ fi "(n)*") | regex_replace("\\", "") | regex_replace("\(n\)\*", "\\n") }}''' create: true no_extra_spaces: true + register: result_ini when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002151 @@ -15932,12 +17337,13 @@ fi - unknown_strategy - name: Prevent user modification of the GNOME3 Login Warning Banner Text - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/banner-message-text$ line: /org/gnome/login-screen/banner-message-text create: true state: present + register: result_lineinfile when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002151 @@ -15952,8 +17358,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update - when: '"gdm" in ansible_facts.packages' + ansible.builtin.command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 @@ -16028,6 +17436,7 @@ Defines the value set as ENCRYPT_METHOD in /etc/login.defs.SHA512 SHA256 YESCRYPT + SHA512|YESCRYPT SHA512|YESCRYPT @@ -16058,19 +17467,18 @@ frequently. escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: $ sudo grep pam_succeed_if /etc/pam.d/sudo If any occurrences of "pam_succeed_if" is returned from the command, this is a finding. - CCI-004895 IA-11 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - OL09-00-002364 - SV-271726r1091890_rule + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + OL09-00-002364 + SV-271726r1091890_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical the user re-authenticate. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then sed -i '/pam_succeed_if/d' /etc/pam.d/sudo @@ -16097,7 +17505,8 @@ fi create: false regexp: pam_succeed_if state: absent - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-002364 - NIST-800-53-IA-11 @@ -16140,7 +17549,6 @@ should be recreated or manually updated. DSS05.04 DSS05.10 DSS06.10 - CCI-000366 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -16157,12 +17565,6 @@ should be recreated or manually updated. SR 1.7 SR 1.8 SR 1.9 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 A.18.1.4 A.9.2.1 A.9.2.4 @@ -16173,7 +17575,7 @@ should be recreated or manually updated. AC-9(1) PR.AC-7 Req-10.2.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 10.2.1.4 10.2.1 10.2 @@ -16181,9 +17583,9 @@ should be recreated or manually updated. information regarding the number of unsuccessful attempts that were made to login to their account allows the user to determine if any unauthorized activity has occurred and gives them an opportunity to notify administrators. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if [ -f /usr/bin/authselect ]; then if authselect list-features sssd | grep -q with-silent-lastlog; then @@ -16338,7 +17740,7 @@ if [ -f /usr/bin/authselect ]; then fi if grep -qP "^\s*session\s+required\s+pam_lastlog.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -16454,7 +17856,7 @@ else fi if grep -qP "^\s*session\s+required\s+pam_lastlog.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -16492,7 +17894,8 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2 - NIST-800-53-AC-9 @@ -16514,8 +17917,10 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_authselect_present.stat.exists tags: - CJIS-5.5.2 @@ -16542,13 +17947,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Displays Last Logon/Access Notification - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -16566,6 +17972,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -16586,7 +17993,8 @@ fi - result_authselect_disable_feature_cmd is not skipped - result_authselect_disable_feature_cmd is success when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-silent-lastlog") tags: @@ -16629,13 +18037,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Displays Last Logon/Access Notification - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -16680,6 +18089,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -16691,6 +18101,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Displays Last Logon/Access Notification - Create an authselect @@ -16699,6 +18110,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -16708,6 +18120,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -16758,6 +18171,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -16850,6 +18265,7 @@ fi state: present register: result_pam_display_login_attempts_add when: + - result_pam_module_display_login_attempts_option_present.found is defined - result_pam_module_display_login_attempts_option_present.found == 0 - name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control @@ -16857,6 +18273,12 @@ fi ansible.builtin.set_fact: pam_module_control: required + - name: Ensure PAM Displays Last Logon/Access Notification - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "silent" option from "pam_lastlog.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -16864,7 +18286,9 @@ fi regexp: (.*session.*{{ pam_module_control | regex_escape() }}.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal - when: '"pam" in ansible_facts.packages' + when: result_pam_file_present.stat.exists + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2 - NIST-800-53-AC-9 @@ -16901,6 +18325,7 @@ risk of a denial-of-service attack. The lockout policy must weigh whether the risk of such a denial-of-service attack outweighs the benefits of thwarting password guessing attacks. + fail_deny Number of failed login attempts before account lockout @@ -16956,7 +18381,7 @@ password guessing attacks. pwhistory_remember - Prevent password re-use using password history lookup + Prevent password reuse using password history lookup 0 1 2 @@ -16998,14 +18423,15 @@ for remediations the first value will be taken' Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. The pam_faillock.so module must be loaded in preauth in /etc/pam.d/password-auth. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003012 - SV-271838r1092226_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003012 + SV-271838r1092226_rule If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent password guessing attacks. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -17032,12 +18458,30 @@ do done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003012 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_password_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003012 - NIST-800-53-AC-7 (a) @@ -17058,13 +18502,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -17082,6 +18527,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -17101,7 +18547,9 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003012 - NIST-800-53-AC-7 (a) @@ -17164,7 +18612,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003012 - NIST-800-53-AC-7 (a) @@ -17185,14 +18635,15 @@ fi Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. The pam_faillock.so module must be loaded in preauth in /etc/pam.d/system-auth. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003011 - SV-271837r1092223_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003011 + SV-271837r1092223_rule If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent password guessing attacks. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -17219,12 +18670,30 @@ do done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003011 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_system_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003011 - NIST-800-53-AC-7 (a) @@ -17245,13 +18714,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -17269,6 +18739,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -17288,7 +18759,9 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003011 - NIST-800-53-AC-7 (a) @@ -17351,7 +18824,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003011 - NIST-800-53-AC-7 (a) @@ -17373,30 +18848,33 @@ fi An SELinux Context must be configured for the pam_faillock.so records directory The dir configuration option in PAM pam_faillock.so module defines where the lockout records is stored. The configured directory must have the correct SELinux context. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003010 - SV-271836r1092637_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003010 + SV-271836r1092637_rule Not having the correct SELinux context on the pam_faillock.so records directory may lead to unauthorized access to the directory. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -FAILLOCK_CONF_FILES="/etc/security/faillock.conf /etc/pam.d/system-auth /etc/pam.d/password-auth" +FAILLOCK_CONF_FILES="/etc/security/faillock.conf" + faillock_dirs=$(grep -oP "^\s*(?:auth.*pam_faillock.so.*)?dir\s*=\s*(\S+)" $FAILLOCK_CONF_FILES \ | sed -r 's/.*=\s*(\S+)/\1/') +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to semanage and restorecon commands to avoid the issue with the command +# not being found. if [ -n "$faillock_dirs" ]; then for dir in $faillock_dirs; do - if ! semanage fcontext -a -t faillog_t "$dir(/.*)?"; then - semanage fcontext -m -t faillog_t "$dir(/.*)?" + if ! /usr/sbin/semanage fcontext -a -t faillog_t "$dir(/.*)?"; then + /usr/sbin/semanage fcontext -m -t faillog_t "$dir(/.*)?" fi if [ ! -e $dir ]; then mkdir -p $dir fi - restorecon -R -v $dir + /usr/sbin/restorecon -R -v $dir done else echo " @@ -17426,10 +18904,10 @@ fi ansible.builtin.shell: grep -oP '^\s*(?:auth.*pam_faillock.so.*)?dir\s*=\s*(\S+)' "{{ item }}" | sed -r 's/.*=\s*(\S+)/\1/' register: faillock_output + changed_when: false + check_mode: false with_items: - /etc/security/faillock.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003010 @@ -17477,11 +18955,11 @@ fi - restrict_strategy - name: An SELinux Context must be configured for the pam_faillock.so records directory - - Set up SELinux context for faillock - ansible.builtin.shell: |- - if ! semanage fcontext -a -t faillog_t "{{ item }}(/.*)?"; then - semanage fcontext -m -t faillog_t "{{ item }}(/.*)?" - fi + - Get SELinux context for faillock directories + ansible.builtin.command: ls -dZ "{{ item }}" + register: faillock_selinux_context + changed_when: false + check_mode: false with_items: '{{ list_faillock_dir }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -17497,12 +18975,36 @@ fi - restrict_strategy - name: An SELinux Context must be configured for the pam_faillock.so records directory - - Restore SELinux context - ansible.builtin.command: restorecon -R -v "{{ item }}" - with_items: '{{ list_faillock_dir }}' + - Set up SELinux context for faillock + ansible.builtin.shell: |- + if ! semanage fcontext -a -t faillog_t "{{ item.item }}(/.*)?"; then + semanage fcontext -m -t faillog_t "{{ item.item }}(/.*)?" + fi + with_items: '{{ faillock_selinux_context.results }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - item != "" + - item.item != "" + - item.stdout is defined + - '"faillog_t" not in item.stdout' + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Restore SELinux context + ansible.builtin.command: restorecon -R -v "{{ item.item }}" + with_items: '{{ faillock_selinux_context.results }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.item != "" + - item.stdout is defined + - '"faillog_t" not in item.stdout' tags: - DISA-STIG-OL09-00-003010 - NIST-800-53-AC-7 (a) @@ -17544,10 +19046,11 @@ fi PAM faillock locks an account due to excessive password failures, this event must be logged. This rule is deprecated in favor of the accounts_passwords_pam_faillock_audit rule.Please consider replacing this rule in your files as it is not expected to receive updates as of version 0.1.65. - CCI-000044 AC-7 (a) Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -17642,16 +19145,33 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*audit' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ audit/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*audit' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ audit/' "$pam_file" fi done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-7 (a) + - account_passwords_pam_faillock_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Account Lockouts Must Be Logged - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17670,13 +19190,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -17693,6 +19214,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -17711,7 +19233,9 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_present.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17772,7 +19296,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_authselect_present.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17787,6 +19313,7 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17803,7 +19330,9 @@ fi regexp: ^\s*audit line: audit state: present - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_faillock_conf_check.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17847,13 +19376,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -17897,6 +19427,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -17908,6 +19439,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -17916,6 +19448,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -17925,6 +19458,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -17973,6 +19507,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -17981,6 +19517,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -17988,6 +19530,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -18028,13 +19571,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -18078,6 +19622,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -18089,6 +19634,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -18097,6 +19643,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -18106,6 +19653,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -18154,6 +19702,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -18162,6 +19712,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -18169,6 +19725,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -18178,7 +19735,9 @@ fi - result_pam_option_removal is changed when: - result_pam_file_present.stat.exists - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_faillock_conf_check.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -18215,7 +19774,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_audit_parameter_is_present.found == 0 - when: not result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_faillock_conf_check.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -18237,7 +19798,6 @@ fi By setting a `dir` in the faillock configuration account lockouts will persist across reboots. This rule is deprecated in favor of the accounts_passwords_pam_faillock_dir rule.Please consider replacing this rule in your files as it is not expected to receive updates as of version 0.1.65. - CCI-000044 AC-7 (ia) Having lockouts persist across reboots ensures that account is only unlocked by an administrator. If the lockouts did not persist across reboots an attack could simply reboot the system to continue brute force attacks against the accounts on the system. @@ -18293,7 +19853,6 @@ updated. DSS06.03 DSS06.10 3.5.8 - CCI-000200 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -18334,14 +19893,14 @@ updated. PR.AC-6 PR.AC-7 Req-8.2.5 - SRG-OS-000077-GPOS-00045 + SRG-OS-000077-GPOS-00045 8.3.7 8.3 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. + Preventing reuse of previous passwords helps ensure that a compromised password is not +reused by a user. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_pam_remember='' var_password_pam_remember_control_flag='' @@ -18544,7 +20103,7 @@ else if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -18589,7 +20148,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -18610,7 +20171,9 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -18638,13 +20201,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -18661,6 +20225,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -18680,6 +20245,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-pwhistory") @@ -18723,13 +20289,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -18773,6 +20340,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -18784,6 +20352,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile @@ -18792,6 +20361,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -18801,6 +20371,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -18849,6 +20420,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -18916,6 +20489,7 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - | (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined @@ -18939,7 +20513,9 @@ fi ansible.builtin.stat: path: /etc/security/pwhistory.conf register: result_pwhistory_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -19002,13 +20578,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile @@ -19052,6 +20629,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -19063,6 +20641,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: password-auth - Create an authselect custom @@ -19071,6 +20650,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -19080,6 +20660,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -19130,6 +20711,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -19138,6 +20721,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: 'Limit Password Reuse: password-auth - Check if {{ pam_file_path }} + file is present' + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: 'Limit Password Reuse: password-auth - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }}' ansible.builtin.replace: @@ -19145,6 +20734,7 @@ fi regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied' @@ -19156,6 +20746,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pwhistory_conf_check.stat.exists tags: @@ -19198,13 +20789,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -19248,6 +20840,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -19259,6 +20852,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile @@ -19267,6 +20861,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -19276,6 +20871,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -19324,6 +20920,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -19414,6 +21012,8 @@ fi state: present register: result_pam_accounts_password_pam_pwhistory_remember_password_auth_add when: + - result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present.found == 0 @@ -19422,7 +21022,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_remember }} \3 register: result_pam_accounts_password_pam_pwhistory_remember_password_auth_edit when: @@ -19437,6 +21037,7 @@ fi - (result_pam_remember_add is defined and result_pam_remember_add.changed) or (result_pam_remember_edit is defined and result_pam_remember_edit.changed) when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_pwhistory_conf_check.stat.exists tags: @@ -19506,7 +21107,6 @@ system, an authselect custom profile must be used to avoid integrity issues in P DSS06.03 DSS06.10 3.5.8 - CCI-000200 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -19547,14 +21147,14 @@ system, an authselect custom profile must be used to avoid integrity issues in P PR.AC-6 PR.AC-7 Req-8.2.5 - SRG-OS-000077-GPOS-00045 + SRG-OS-000077-GPOS-00045 8.3.7 8.3 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. + Preventing reuse of previous passwords helps ensure that a compromised password is not +reused by a user. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_pam_remember='' var_password_pam_remember_control_flag='' @@ -19757,7 +21357,7 @@ else if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -19802,7 +21402,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -19823,7 +21425,9 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -19851,13 +21455,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -19874,6 +21479,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -19893,6 +21499,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-pwhistory") @@ -19936,13 +21543,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -19986,6 +21594,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -19997,6 +21606,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile @@ -20005,6 +21615,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -20014,6 +21625,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -20062,6 +21674,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -20129,6 +21743,7 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - | (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined @@ -20152,7 +21767,9 @@ fi ansible.builtin.stat: path: /etc/security/pwhistory.conf register: result_pwhistory_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -20215,13 +21832,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile @@ -20265,6 +21883,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -20276,6 +21895,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile @@ -20284,6 +21904,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -20293,6 +21914,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -20343,6 +21965,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -20351,6 +21975,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: 'Limit Password Reuse: system-auth - Check if {{ pam_file_path }} file + is present' + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: 'Limit Password Reuse: system-auth - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }}' ansible.builtin.replace: @@ -20358,6 +21988,7 @@ fi regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied' ansible.builtin.command: @@ -20368,6 +21999,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pwhistory_conf_check.stat.exists tags: @@ -20410,13 +22042,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -20460,6 +22093,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -20471,6 +22105,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile @@ -20479,6 +22114,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -20488,6 +22124,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -20536,6 +22173,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -20626,6 +22265,8 @@ fi state: present register: result_pam_accounts_password_pam_pwhistory_remember_system_auth_add when: + - result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present.found == 0 @@ -20634,7 +22275,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_remember }} \3 register: result_pam_accounts_password_pam_pwhistory_remember_system_auth_edit when: @@ -20649,6 +22290,7 @@ fi - (result_pam_remember_add is defined and result_pam_remember_add.changed) or (result_pam_remember_edit is defined and result_pam_remember_edit.changed) when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_pwhistory_conf_check.stat.exists tags: @@ -20700,7 +22342,6 @@ system, an authselect custom profile must be used to avoid integrity issues in P DSS06.03 DSS06.10 3.5.8 - CCI-000200 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -20741,15 +22382,15 @@ system, an authselect custom profile must be used to avoid integrity issues in P PR.AC-6 PR.AC-7 Req-8.2.5 - SRG-OS-000077-GPOS-00045 + SRG-OS-000077-GPOS-00045 R31 8.3.7 8.3 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. - + Preventing reuse of previous passwords helps ensure that a compromised password is not +reused by a user. + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_unix_remember='' @@ -20953,7 +22594,7 @@ else if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_unix_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_remember \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_unix_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -20992,7 +22633,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -21013,8 +22656,10 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_authselect_present.stat.exists tags: - CJIS-5.6.2.1.1 @@ -21039,13 +22684,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -21062,6 +22708,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -21081,7 +22728,8 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-pwhistory") tags: @@ -21120,13 +22768,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -21170,6 +22819,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -21181,6 +22831,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Limit Password Reuse - Create an authselect custom profile based on the @@ -21189,6 +22840,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -21198,6 +22850,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -21244,6 +22897,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -21310,7 +22965,8 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - | (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined tags: @@ -21333,7 +22989,9 @@ fi ansible.builtin.stat: path: /etc/security/pwhistory.conf register: result_pwhistory_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -21391,13 +23049,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile @@ -21441,6 +23100,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -21452,6 +23112,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Limit Password Reuse - Create an authselect custom profile based on @@ -21460,6 +23121,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -21469,6 +23131,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -21516,6 +23179,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -21524,6 +23189,11 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Limit Password Reuse - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Limit Password Reuse - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -21531,6 +23201,7 @@ fi regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Limit Password Reuse - Ensure authselect changes are applied ansible.builtin.command: @@ -21541,7 +23212,8 @@ fi when: - result_pam_file_present.stat.exists when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pwhistory_conf_check.stat.exists tags: - CJIS-5.6.2.1.1 @@ -21579,13 +23251,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -21629,6 +23302,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -21640,6 +23314,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Limit Password Reuse - Create an authselect custom profile based on the @@ -21648,6 +23323,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -21657,6 +23333,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -21703,6 +23380,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -21793,6 +23472,8 @@ fi state: present register: result_pam_accounts_password_pam_unix_remember_add when: + - result_pam_module_accounts_password_pam_unix_remember_option_present.found is + defined - result_pam_module_accounts_password_pam_unix_remember_option_present.found == 0 @@ -21801,7 +23482,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_unix_remember }} \3 register: result_pam_accounts_password_pam_unix_remember_edit when: @@ -21816,7 +23497,8 @@ fi - (result_pam_remember_add is defined and result_pam_remember_add.changed) or (result_pam_remember_edit is defined and result_pam_remember_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - not result_pwhistory_conf_check.stat.exists tags: - CJIS-5.6.2.1.1 @@ -21844,13 +23526,15 @@ fi Account Lockouts Must Be Logged PAM faillock locks an account due to excessive password failures, this event must be logged. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003022 - SV-271841r1092235_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003022 + SV-271841r1092235_rule Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -21945,16 +23629,36 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*audit' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ audit/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*audit' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ audit/' "$pam_file" fi done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003022 + - NIST-800-53-AC-7 (a) + - accounts_passwords_pam_faillock_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Account Lockouts Must Be Logged - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -21974,13 +23678,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -21997,6 +23702,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -22015,7 +23721,10 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22077,7 +23786,10 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22093,6 +23805,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22110,7 +23825,10 @@ fi regexp: ^\s*audit line: audit state: present - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - result_faillock_conf_check.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22155,13 +23873,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -22205,6 +23924,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -22216,6 +23936,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -22224,6 +23945,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -22233,6 +23955,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -22281,6 +24004,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -22289,6 +24014,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -22296,6 +24027,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -22336,13 +24068,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -22386,6 +24119,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -22397,6 +24131,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -22405,6 +24140,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -22414,6 +24150,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -22462,6 +24199,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -22470,6 +24209,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -22477,6 +24222,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -22486,7 +24232,10 @@ fi - result_pam_option_removal is changed when: - result_pam_file_present.stat.exists - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - result_faillock_conf_check.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22524,7 +24273,10 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_audit_parameter_is_present.found == 0 - when: not result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not result_faillock_conf_check.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22572,8 +24324,6 @@ parameters should be defined in faillock.conf file.DSS05.10 DSS06.10 3.1.8 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -22590,20 +24340,6 @@ parameters should be defined in faillock.conf file.SR 1.7 SR 1.8 SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.9.2.1 A.9.2.4 @@ -22615,20 +24351,33 @@ parameters should be defined in faillock.conf file.PR.AC-7 FIA_AFL.1 Req-8.1.6 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 R31 A.30.SEC-OL1 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.4 8.3 - OL09-00-003020 - SV-271839r1092229_rule + OL09-00-003020 + SV-271839r1092229_rule By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_deny='' @@ -22729,12 +24478,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*deny' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*deny' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"deny"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"deny"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"deny"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"deny"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" fi done fi @@ -22767,7 +24516,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-003020 @@ -22794,13 +24545,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts After Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -22817,6 +24569,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -22837,6 +24590,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -22908,6 +24662,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -22936,7 +24691,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-003020 @@ -22961,6 +24718,7 @@ fi line: deny = {{ var_accounts_passwords_pam_faillock_deny }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -23014,13 +24772,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts After Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -23065,6 +24824,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -23076,6 +24836,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts After Failed Password Attempts - Create an authselect @@ -23084,6 +24845,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -23093,6 +24855,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -23143,6 +24906,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -23151,6 +24916,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts After Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -23158,6 +24929,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes are applied @@ -23200,13 +24972,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts After Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -23251,6 +25024,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -23262,6 +25036,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts After Failed Password Attempts - Create an authselect @@ -23270,6 +25045,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -23279,6 +25055,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -23329,6 +25106,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -23337,6 +25116,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts After Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -23344,6 +25129,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes are applied @@ -23355,6 +25141,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -23443,6 +25230,7 @@ fi when: - result_pam_faillock_deny_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -23492,8 +25280,6 @@ parameters should be defined in faillock.conf file.DSS05.04 DSS05.10 DSS06.10 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -23510,9 +25296,21 @@ parameters should be defined in faillock.conf file.SR 1.7 SR 1.8 SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(b) + IA-5(c) + PR.AC-7 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 0421 0422 - 0431 0974 1173 1401 @@ -23524,27 +25322,14 @@ parameters should be defined in faillock.conf file.1559 1560 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(b) - IA-5(c) - PR.AC-7 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - R31 - OL09-00-003021 - SV-271840r1092232_rule + OL09-00-003021 + SV-271840r1092232_rule By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then if [ -f /usr/bin/authselect ]; then if ! authselect check; then @@ -23640,8 +25425,8 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*even_deny_root' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ even_deny_root/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*even_deny_root' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ even_deny_root/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ even_deny_root/' "$pam_file" fi done @@ -23671,7 +25456,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) @@ -23694,13 +25481,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the root Account for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -23718,6 +25506,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -23738,6 +25527,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -23805,6 +25595,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -23824,7 +25615,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) @@ -23845,6 +25638,7 @@ fi line: even_deny_root state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -23894,13 +25688,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the root Account for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -23945,6 +25740,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -23956,6 +25752,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Configure the root Account for Failed Password Attempts - Create an @@ -23964,6 +25761,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -23973,6 +25771,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -24023,6 +25822,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -24031,6 +25832,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Configure the root Account for Failed Password Attempts - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -24038,6 +25845,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Configure the root Account for Failed Password Attempts - Ensure authselect changes are applied @@ -24080,13 +25888,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the root Account for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -24131,6 +25940,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -24142,6 +25952,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Configure the root Account for Failed Password Attempts - Create an @@ -24150,6 +25961,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -24159,6 +25971,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -24209,6 +26022,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -24217,6 +26032,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Configure the root Account for Failed Password Attempts - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -24224,6 +26045,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Configure the root Account for Failed Password Attempts - Ensure authselect changes are applied @@ -24235,6 +26057,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -24291,6 +26114,7 @@ fi when: - result_pam_faillock_even_deny_root_parameter_is_present.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -24317,7 +26141,7 @@ fi This rule ensures that the system lock out accounts using pam_faillock.so persist after system reboot. From "pam_faillock" man pages: Note that the default directory that "pam_faillock" uses is usually cleared on system -boot so the access will be reenabled after system reboot. If that is undesirable, a different +boot so the access will be re-enabled after system reboot. If that is undesirable, a different tally directory must be set with the "dir" option. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully @@ -24325,7 +26149,12 @@ defined to work as expected. In order to avoid errors when manually editing thes recommended to use the appropriate tools, such as authselect or authconfig, depending on the OS version. -The chosen profile expects the directory to be . +The chosen profile expects the directory to be . + +To configure the tally directory, add the following line to /etc/security/faillock.conf: +dir = + + If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be @@ -24333,20 +26162,19 @@ aborted in order to preserve intentional changes. In this case, an informative m be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock parameters should be defined in faillock.conf file. - CCI-000044 AC-7(b) AC-7(a) AC-7.1(ii) - SRG-OS-000021-GPOS-00005 - SRG-OS-000329-GPOS-00128 - OL09-00-003023 - SV-271842r1092238_rule + SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + OL09-00-003023 + SV-271842r1092238_rule Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. In combination with the silent option, user enumeration attacks are also mitigated. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_dir='' @@ -24447,12 +26275,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*dir' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ dir='"$var_accounts_passwords_pam_faillock_dir"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*dir' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ dir='"$var_accounts_passwords_pam_faillock_dir"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ dir='"$var_accounts_passwords_pam_faillock_dir"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"dir"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"dir"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"dir"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"dir"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" fi done fi @@ -24468,8 +26296,11 @@ if ! rpm -q --quiet "policycoreutils-python-utils" ; then fi mkdir -p "$var_accounts_passwords_pam_faillock_dir" -semanage fcontext -a -t faillog_t "$var_accounts_passwords_pam_faillock_dir(/.*)?" -restorecon -R -v "$var_accounts_passwords_pam_faillock_dir" +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to semanage and restorecon commands to avoid the issue with the command +# not being found. +/usr/sbin/semanage fcontext -a -t faillog_t "$var_accounts_passwords_pam_faillock_dir(/.*)?" +/usr/sbin/restorecon -R -v "$var_accounts_passwords_pam_faillock_dir" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -24494,7 +26325,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -24515,13 +26348,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts Must Persist - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -24538,6 +26372,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -24557,6 +26392,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -24622,6 +26458,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -24646,7 +26483,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -24666,6 +26505,7 @@ fi line: dir = {{ var_accounts_passwords_pam_faillock_dir }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -24711,13 +26551,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts Must Persist - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -24761,6 +26602,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -24772,6 +26614,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts Must Persist - Create an authselect custom profile based @@ -24780,6 +26623,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -24789,6 +26633,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -24837,6 +26682,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -24845,6 +26692,11 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts Must Persist - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts Must Persist - Ensure the "dir" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -24852,6 +26704,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdir\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts Must Persist - Ensure authselect changes are applied ansible.builtin.command: @@ -24889,13 +26742,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts Must Persist - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -24939,6 +26793,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -24950,6 +26805,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts Must Persist - Create an authselect custom profile based @@ -24958,6 +26814,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -24967,6 +26824,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -25015,6 +26873,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -25023,6 +26883,11 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts Must Persist - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts Must Persist - Ensure the "dir" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25030,6 +26895,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdir\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts Must Persist - Ensure authselect changes are applied ansible.builtin.command: @@ -25040,6 +26906,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -25124,6 +26991,7 @@ fi when: - result_pam_faillock_dir_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -25146,7 +27014,9 @@ fi - python3-libselinux - python3-policycoreutils - policycoreutils-python-utils - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25159,12 +27029,37 @@ fi - medium_severity - no_reboot_needed -- name: Lock Accounts Must Persist - Create the tally directory if it does not exist +- name: Lock Accounts Must Persist - Create the faillock directory if it does not + exist ansible.builtin.file: path: '{{ var_accounts_passwords_pam_faillock_dir }}' state: directory setype: faillog_t - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-003023 + - NIST-800-53-AC-7(a) + - NIST-800-53-AC-7(b) + - NIST-800-53-AC-7.1(ii) + - accounts_passwords_pam_faillock_dir + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Lock Accounts Must Persist - Get SELinux context for faillock directory + ansible.builtin.command: + cmd: ls -dZ {{ var_accounts_passwords_pam_faillock_dir }} + register: faillock_selinux_context + changed_when: false + check_mode: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25185,7 +27080,10 @@ fi failed_when: false changed_when: - result_accounts_passwords_pam_faillock_dir_semanage.rc == 0 - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - '"faillog_t" not in faillock_selinux_context.stdout' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25202,7 +27100,10 @@ fi ansible.builtin.command: cmd: restorecon -R "{{ var_accounts_passwords_pam_faillock_dir }}" register: result_accounts_passwords_pam_faillock_dir_restorecon - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - '"faillog_t" not in faillock_selinux_context.stdout' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25249,8 +27150,6 @@ parameters should be defined in faillock.conf file.DSS05.04 DSS05.10 DSS06.10 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -25267,9 +27166,21 @@ parameters should be defined in faillock.conf file.SR 1.7 SR 1.8 SR 1.9 + A.18.1.4 + A.9.2.1 + A.9.2.4 + A.9.3.1 + A.9.4.2 + A.9.4.3 + CM-6(a) + AC-7(a) + PR.AC-7 + FIA_AFL.1 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 0421 0422 - 0431 0974 1173 1401 @@ -25281,27 +27192,14 @@ parameters should be defined in faillock.conf file.1559 1560 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(a) - PR.AC-7 - FIA_AFL.1 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - R31 - OL09-00-002416 - SV-271754r1091974_rule + OL09-00-002416 + SV-271754r1091974_rule By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_fail_interval='' @@ -25402,12 +27300,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*fail_interval' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ fail_interval='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*fail_interval' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ fail_interval='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ fail_interval='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"fail_interval"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"fail_interval"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"fail_interval"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"fail_interval"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" fi done fi @@ -25435,7 +27333,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) @@ -25457,13 +27357,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Interval For Counting Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -25481,6 +27382,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -25501,6 +27403,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -25567,6 +27470,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -25590,7 +27494,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) @@ -25610,6 +27516,7 @@ fi line: fail_interval = {{ var_accounts_passwords_pam_faillock_fail_interval }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -25658,13 +27565,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Interval For Counting Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -25709,6 +27617,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -25720,6 +27629,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Interval For Counting Failed Password Attempts - Create an authselect @@ -25728,6 +27638,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -25737,6 +27648,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -25787,6 +27699,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -25795,6 +27709,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Interval For Counting Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25802,6 +27722,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bfail_interval\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Interval For Counting Failed Password Attempts - Ensure authselect changes are applied @@ -25844,13 +27765,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Interval For Counting Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -25895,6 +27817,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -25906,6 +27829,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Interval For Counting Failed Password Attempts - Create an authselect @@ -25914,6 +27838,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -25923,6 +27848,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -25973,6 +27899,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -25981,6 +27909,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Interval For Counting Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25988,6 +27922,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bfail_interval\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Interval For Counting Failed Password Attempts - Ensure authselect changes are applied @@ -25999,6 +27934,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -26084,6 +28020,7 @@ fi when: - result_pam_faillock_fail_interval_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -26143,8 +28080,6 @@ parameters should be defined in faillock.conf file.DSS05.10 DSS06.10 3.1.8 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -26161,20 +28096,6 @@ parameters should be defined in faillock.conf file.SR 1.7 SR 1.8 SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.9.2.1 A.9.2.4 @@ -26186,20 +28107,33 @@ parameters should be defined in faillock.conf file.PR.AC-7 FIA_AFL.1 Req-8.1.7 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 R31 A.30.SEC-OL1 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.4 8.3 - OL09-00-002417 - SV-271755r1091977_rule + OL09-00-002417 + SV-271755r1091977_rule By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_unlock_time='' @@ -26300,12 +28234,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*unlock_time' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*unlock_time' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"unlock_time"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"unlock_time"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"unlock_time"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"unlock_time"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" fi done fi @@ -26338,7 +28272,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-002417 @@ -26365,13 +28301,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Lockout Time for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -26388,6 +28325,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -26408,6 +28346,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -26479,6 +28418,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -26507,7 +28447,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-002417 @@ -26532,6 +28474,7 @@ fi line: unlock_time = {{ var_accounts_passwords_pam_faillock_unlock_time }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -26585,13 +28528,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Lockout Time for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -26636,6 +28580,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -26647,6 +28592,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Lockout Time for Failed Password Attempts - Create an authselect @@ -26655,6 +28601,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -26664,6 +28611,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -26714,6 +28662,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -26722,6 +28672,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Lockout Time for Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -26729,6 +28685,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes are applied @@ -26771,13 +28728,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Lockout Time for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -26822,6 +28780,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -26833,6 +28792,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Lockout Time for Failed Password Attempts - Create an authselect @@ -26841,6 +28801,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -26850,6 +28811,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -26900,6 +28862,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -26908,6 +28872,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Lockout Time for Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -26915,6 +28885,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes are applied @@ -26926,6 +28897,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -27016,6 +28988,7 @@ fi when: - result_pam_faillock_unlock_time_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -27058,6 +29031,7 @@ password requirements. The man pages pam_pwquality(8) provide information on the capabilities and configuration of each. + Set Password Quality Requirements with pam_pwquality The pam_pwquality PAM module can be configured to meet @@ -27202,7 +29176,6 @@ length credit for each digit. Modify the dcredit setting DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -27227,20 +29200,6 @@ length credit for each digit. Modify the dcredit setting SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -27260,12 +29219,25 @@ length credit for each digit. Modify the dcredit setting PR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000071-GPOS-00039 + SRG-OS-000071-GPOS-00039 R31 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.6 8.3 - OL09-00-001020 - SV-271616r1091560_rule + OL09-00-001020 + SV-271616r1091560_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force @@ -27277,14 +29249,18 @@ to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring digits makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_dcredit='' +if grep -sq dcredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/dcredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -27336,6 +29312,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdcredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdcredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -27388,12 +29413,65 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Find + pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + dcredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bdcredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) @@ -27435,13 +29513,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -27486,6 +29565,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -27497,6 +29577,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - @@ -27505,6 +29586,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -27514,6 +29596,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -27564,6 +29647,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -27572,6 +29657,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -27580,6 +29671,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bdcredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure authselect changes are applied @@ -27589,7 +29681,244 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Define + the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Get authselect current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + Change the PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Define + a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bdcredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001020 @@ -27614,7 +29943,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*dcredit line: dcredit = {{ var_password_pam_dcredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) @@ -27643,15 +29974,14 @@ fi Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words The pam_pwquality module's dictcheck check if passwords contains dictionary words. When dictcheck is set to 1 passwords will be checked for dictionary words. - CCI-000366 IA-5(c) IA-5(1)(a) CM-6(a) IA-5(4) - SRG-OS-000480-GPOS-00225 - SRG-OS-000072-GPOS-00040 - OL09-00-001125 - SV-271637r1091623_rule + SRG-OS-000480-GPOS-00225 + SRG-OS-000072-GPOS-00040 + OL09-00-001125 + SV-271637r1091623_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -27663,14 +29993,18 @@ password is compromised. Passwords with dictionary words may be more vulnerable to password-guessing attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_dictcheck='' +if grep -sq dictcheck /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/dictcheck/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -27722,6 +30056,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdictcheck\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdictcheck\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -27771,12 +30154,59 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure dictcheck is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bdictcheck\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) @@ -27815,13 +30245,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -27867,6 +30298,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -27878,6 +30310,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary @@ -27886,6 +30319,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -27895,6 +30329,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -27946,6 +30381,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -27954,6 +30391,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Ensure the "dictcheck" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -27962,6 +30405,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bdictcheck\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Ensure authselect changes are applied @@ -27971,7 +30415,240 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Get authselect current features to also enable them in the custom + profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Change the PAM file to be edited according to the custom authselect + profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure the "dictcheck" option from "pam_pwquality.so" is not present + in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bdictcheck\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001125 @@ -27993,7 +30670,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*dictcheck line: dictcheck = {{ var_password_pam_dictcheck }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) @@ -28036,7 +30715,6 @@ when changing passwords. DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -28078,9 +30756,9 @@ when changing passwords. PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 - OL09-00-001025 - SV-271617r1091563_rule + SRG-OS-000072-GPOS-00040 + OL09-00-001025 + SV-271617r1091563_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts @@ -28096,14 +30774,18 @@ before the password is compromised. Requiring a minimum number of different characters during password changes ensures that newly changed passwords should not resemble previously compromised ones. Note that passwords which are changed on compromised systems will still be compromised, however. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_difok='' +if grep -sq difok /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/difok/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -28155,6 +30837,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdifok\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdifok\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -28205,12 +30936,61 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Ensure difok is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bdifok\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - DISA-STIG-OL09-00-001025 @@ -28250,13 +31030,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -28301,6 +31082,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -28312,6 +31094,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters @@ -28320,6 +31103,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -28329,6 +31113,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -28379,6 +31164,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -28387,6 +31174,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Ensure the "difok" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -28395,6 +31188,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bdifok\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Ensure authselect changes are applied @@ -28404,7 +31198,240 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Get authselect current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Change the PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure the "difok" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bdifok\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - CJIS-5.6.2.1.1 @@ -28427,7 +31454,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*difok line: difok = {{ var_password_pam_difok }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - DISA-STIG-OL09-00-001025 @@ -28456,20 +31485,19 @@ fi enforcing password complexity for the root user. Enable the enforce_for_root setting in /etc/security/pwquality.conf to require the root user to use complex passwords. - CCI-004066 IA-5(c) IA-5(1)(a) CM-6(a) IA-5(4) - SRG-OS-000072-GPOS-00040 - SRG-OS-000071-GPOS-00039 - SRG-OS-000070-GPOS-00038 - SRG-OS-000266-GPOS-00101 - SRG-OS-000078-GPOS-00046 - SRG-OS-000480-GPOS-00225 - SRG-OS-000069-GPOS-00037 - OL09-00-001045 - SV-271621r1091575_rule + SRG-OS-000072-GPOS-00040 + SRG-OS-000071-GPOS-00039 + SRG-OS-000070-GPOS-00038 + SRG-OS-000266-GPOS-00101 + SRG-OS-000078-GPOS-00046 + SRG-OS-000480-GPOS-00225 + SRG-OS-000069-GPOS-00037 + OL09-00-001045 + SV-271621r1091575_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -28477,9 +31505,9 @@ password in resisting attempts at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then if [ -e "/etc/security/pwquality.conf" ] ; then @@ -28517,13 +31545,15 @@ fi - restrict_strategy - name: Ensure PAM Enforces Password Requirements - Enforce for root User - lineinfile: + ansible.builtin.lineinfile: path: /etc/security/pwquality.conf create: true regexp: '' line: enforce_for_root state: present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001045 - NIST-800-53-CM-6(a) @@ -28562,7 +31592,6 @@ length credit for each lowercase character. Modify the lcreditDSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -28587,20 +31616,6 @@ length credit for each lowercase character. Modify the lcreditSR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -28620,12 +31635,25 @@ length credit for each lowercase character. Modify the lcreditPR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000070-GPOS-00038 + SRG-OS-000070-GPOS-00038 R31 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.6 8.3 - OL09-00-001015 - SV-271615r1091557_rule + OL09-00-001015 + SV-271615r1091557_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force @@ -28633,17 +31661,21 @@ attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of -possble combinations that need to be tested before the password is compromised. +possible combinations that need to be tested before the password is compromised. Requiring a minimum number of lowercase characters makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_lcredit='' +if grep -sq lcredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/lcredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -28695,6 +31727,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\blcredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\blcredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -28747,12 +31828,65 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Ensure lcredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\blcredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) @@ -28794,13 +31928,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -28845,6 +31980,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -28856,6 +31992,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters @@ -28864,6 +32001,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -28873,6 +32011,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -28923,6 +32062,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -28931,6 +32072,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -28939,6 +32086,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\blcredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Ensure authselect changes are applied @@ -28948,7 +32096,244 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Get authselect current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Change the PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\blcredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001015 @@ -28973,7 +32358,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*lcredit line: lcredit = {{ var_password_pam_lcredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) @@ -29016,7 +32403,6 @@ to prevent a run of (DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -29058,10 +32444,10 @@ to prevent a run of (PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 - SRG-OS-000730-GPOS-00190 - OL09-00-001030 - SV-271618r1091566_rule + SRG-OS-000072-GPOS-00040 + SRG-OS-000730-GPOS-00190 + OL09-00-001030 + SV-271618r1091566_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -29069,14 +32455,18 @@ attempts at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex a password, the greater the number of possible combinations that need to be tested before the password is compromised. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_maxclassrepeat='' +if grep -sq maxclassrepeat /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/maxclassrepeat/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -29128,6 +32518,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bmaxclassrepeat\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -29177,13 +32616,60 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure maxclassrepeat is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bmaxclassrepeat\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) @@ -29226,6 +32712,7 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating @@ -29233,7 +32720,7 @@ fi integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -29281,6 +32768,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -29293,6 +32781,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating @@ -29302,6 +32791,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -29312,6 +32802,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -29365,6 +32856,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -29374,6 +32867,13 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Ensure the "maxclassrepeat" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -29382,6 +32882,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Ensure authselect changes are applied @@ -29391,7 +32892,255 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if /etc/pam.d/password-auth file + is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define the PAM file to be edited as a + local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if system relies on authselect + tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure authselect custom profile is used + if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check integrity of authselect current + profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Informative message based on the authselect + integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define the current authselect profile + as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define the new authselect custom profile + as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Get authselect current features to + also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if any custom profile with the + same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Create an authselect custom profile + based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Create an authselect custom profile + based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure the authselect custom profile + is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Restore the authselect features in + the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Change the PAM file to be edited according + to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure the "maxclassrepeat" option from + "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001030 @@ -29414,7 +33163,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*maxclassrepeat line: maxclassrepeat = {{ var_password_pam_maxclassrepeat }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) @@ -29454,7 +33205,6 @@ run of (DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -29495,9 +33245,9 @@ run of (PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 - OL09-00-001035 - SV-271619r1091569_rule + SRG-OS-000072-GPOS-00040 + OL09-00-001035 + SV-271619r1091569_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -29509,14 +33259,18 @@ password is compromised. Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_maxrepeat='' +if grep -sq maxrepeat /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/maxrepeat/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -29568,6 +33322,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bmaxrepeat\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -29616,12 +33419,57 @@ fi tags: - always +- name: Set Password Maximum Consecutive Repeating Characters - Find pwquality.conf.d + files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Password Maximum Consecutive Repeating Characters - Ensure maxrepeat is + not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bmaxrepeat\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Set Password Maximum Consecutive Repeating Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) @@ -29659,13 +33507,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Password Maximum Consecutive Repeating Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -29710,6 +33559,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -29721,6 +33571,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Password Maximum Consecutive Repeating Characters - Create an authselect @@ -29729,6 +33580,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -29738,6 +33590,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -29788,6 +33641,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -29796,6 +33651,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Password Maximum Consecutive Repeating Characters - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Password Maximum Consecutive Repeating Characters - Ensure the "maxrepeat" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -29803,6 +33664,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect changes are applied @@ -29812,7 +33674,235 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Password Maximum Consecutive Repeating Characters - Check if /etc/pam.d/password-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Password Maximum Consecutive Repeating Characters - Check the proper remediation + for the system + block: + + - name: Set Password Maximum Consecutive Repeating Characters - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Set Password Maximum Consecutive Repeating Characters - Check if system + relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect + custom profile is used if authselect is present + block: + + - name: Set Password Maximum Consecutive Repeating Characters - Check integrity + of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Set Password Maximum Consecutive Repeating Characters - Informative message + based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Set Password Maximum Consecutive Repeating Characters - Get authselect + current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Set Password Maximum Consecutive Repeating Characters - Define the current + authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Set Password Maximum Consecutive Repeating Characters - Define the new + authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Set Password Maximum Consecutive Repeating Characters - Get authselect + current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Set Password Maximum Consecutive Repeating Characters - Check if any custom + profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Set Password Maximum Consecutive Repeating Characters - Create an authselect + custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Password Maximum Consecutive Repeating Characters - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure the authselect + custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Set Password Maximum Consecutive Repeating Characters - Restore the authselect + features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Set Password Maximum Consecutive Repeating Characters - Change the PAM + file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Set Password Maximum Consecutive Repeating Characters - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Set Password Maximum Consecutive Repeating Characters - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure the "maxrepeat" + option from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001035 @@ -29833,7 +33923,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*maxrepeat line: maxrepeat = {{ var_password_pam_maxrepeat }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) @@ -29883,7 +33975,6 @@ differing categories of characters when changing passwords.DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -29908,20 +33999,6 @@ differing categories of characters when changing passwords.SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -29939,11 +34016,24 @@ differing categories of characters when changing passwords.PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 + SRG-OS-000072-GPOS-00040 R68 A.11.SEC-OL3 - OL09-00-001040 - SV-271620r1091572_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-001040 + SV-271620r1091572_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -29956,14 +34046,18 @@ the password is compromised. Requiring a minimum number of character categories makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_minclass='' +if grep -sq minclass /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/minclass/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -30015,6 +34109,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bminclass\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bminclass\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -30064,12 +34207,59 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Ensure minclass is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bminclass\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) @@ -30108,13 +34298,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -30159,6 +34350,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -30170,6 +34362,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories @@ -30178,6 +34371,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -30187,6 +34381,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -30237,6 +34432,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -30245,6 +34442,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Ensure the "minclass" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -30253,6 +34456,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bminclass\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Ensure authselect changes are applied @@ -30262,7 +34466,238 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Get authselect current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Change the PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure the "minclass" option from "pam_pwquality.so" is not present in {{ + pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bminclass\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001040 @@ -30284,7 +34719,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*minclass line: minclass = {{ var_password_pam_minclass }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) @@ -30324,7 +34761,6 @@ after pam_pwquality to set minimum password length requirements.DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -30349,20 +34785,6 @@ after pam_pwquality to set minimum password length requirements.SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -30382,12 +34804,27 @@ after pam_pwquality to set minimum password length requirements.PR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000078-GPOS-00046 + SRG-OS-000078-GPOS-00046 R31 R68 A.11.SEC-OL3 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.6 8.3 + OL09-00-001105 + SV-271633r1091611_rule The shorter the password, the lower the number of possible combinations that need to be tested before the password is compromised. @@ -30397,14 +34834,18 @@ Password length is one factor of several that helps to determine strength and how long it takes to crack a password. Use of more characters in a password helps to exponentially increase the time and/or resources required to compromise the password. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_minlen='' +if grep -sq minlen /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/minlen/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -30456,6 +34897,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bminlen\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bminlen\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -30489,6 +34979,7 @@ fi manager: auto tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30508,14 +34999,70 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Find pwquality.conf.d + files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure minlen + is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bminlen\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30555,13 +35102,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Length - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -30606,6 +35154,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -30617,6 +35166,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Length - Create an @@ -30625,6 +35175,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -30634,6 +35185,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -30684,6 +35236,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -30692,6 +35246,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the "minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -30699,6 +35259,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bminlen\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect changes are applied @@ -30708,10 +35269,249 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if /etc/pam.d/password-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check the proper + remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Define the + PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if system + relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect + custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check integrity + of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Informative + message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Get authselect + current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Define the + current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Define the + new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Get authselect + current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if + any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Create an + authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Create an + authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the + authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Restore the + authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Change the + PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Define a fact + for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the + "minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bminlen\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30733,9 +35533,12 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*minlen line: minlen = {{ var_password_pam_minlen }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30778,7 +35581,6 @@ to require use of a special character in passwords. DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -30803,20 +35605,6 @@ to require use of a special character in passwords. SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -30835,10 +35623,23 @@ to require use of a special character in passwords. PR.AC-6 PR.AC-7 FMT_SMF_EXT.1 - SRG-OS-000266-GPOS-00101 + SRG-OS-000266-GPOS-00101 R31 - OL09-00-001120 - SV-271636r1091620_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-001120 + SV-271636r1091620_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force @@ -30850,14 +35651,18 @@ to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring a minimum number of special characters makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_ocredit='' +if grep -sq ocredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/ocredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -30909,6 +35714,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bocredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bocredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -30958,12 +35812,59 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Find + pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure + ocredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bocredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) @@ -31002,13 +35903,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -31053,6 +35955,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -31064,6 +35967,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters @@ -31072,6 +35976,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -31081,6 +35986,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -31131,6 +36037,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -31139,6 +36047,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -31147,6 +36061,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bocredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure authselect changes are applied @@ -31156,7 +36071,238 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Check + if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Check + the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Get authselect current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - Change the PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bocredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001120 @@ -31178,7 +36324,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*ocredit line: ocredit = {{ var_password_pam_ocredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) @@ -31206,17 +36354,16 @@ fi Edit the password section in /etc/pam.d/password-auth to show password requisite pam_pwquality.so. - CCI-004066 - SRG-OS-000069-GPOS-00037 - SRG-OS-000070-GPOS-00038 - SRG-OS-000480-GPOS-00227 - OL09-00-001010 - SV-271614r1091554_rule + SRG-OS-000069-GPOS-00037 + SRG-OS-000070-GPOS-00038 + SRG-OS-000480-GPOS-00227 + OL09-00-001010 + SV-271614r1091554_rule Enabling PAM password complexity permits to enforce strong passwords and consequently makes the system less prone to dictionary attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then if [ -e "/etc/pam.d/password-auth" ] ; then PAM_FILE_PATH="/etc/pam.d/password-auth" @@ -31300,7 +36447,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001010 - accounts_password_pam_pwquality_password_auth @@ -31335,13 +36484,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM password complexity module is enabled in password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -31386,6 +36536,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -31397,6 +36548,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM password complexity module is enabled in password-auth - Create @@ -31405,6 +36557,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -31414,6 +36567,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -31464,6 +36618,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -31542,7 +36698,8 @@ fi (result_pam_accounts_password_pam_pwquality_password_auth_add is defined and result_pam_accounts_password_pam_pwquality_password_auth_add.changed) or (result_pam_accounts_password_pam_pwquality_password_auth_edit is defined and result_pam_accounts_password_pam_pwquality_password_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001010 @@ -31560,21 +36717,733 @@ fi + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session in /etc/security/pwquality.conf + To configure the number of retry prompts that are permitted per-session: +Edit the /etc/security/pwquality.conf to include +retry= + , or a lower value if site +policy is more restrictive. The profile requirement is a maximum of retry= + prompts +per session. + SRG-OS-000069-GPOS-00037 + OL09-00-001001 + SV-271612r1091548_rule + Setting the password retry prompts that are permitted on a per-session basis to a low value +requires some software, such as SSH, to re-connect. This can slow down and +draw additional attention to some types of password-guessing attacks. Note that this +is different from account lockout, which is provided by the pam_faillock module. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_password_pam_retry='' + + + +if grep -sq retry /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/retry/d" /etc/security/pwquality.conf.d/*.conf +fi + + + +if [ -e "/etc/pam.d/system-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/system-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/system-auth was not found" >&2 +fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi + + + + +# Strip any search characters in the key arg so that the key can be replaced without +# adding any search characters to the config file. +stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^retry") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_retry" + +# If the key exists, change it. Otherwise, add it to the config_file. +# We search for the key string followed by a word boundary (matched by \>), +# so if we search for 'setting', 'setting2' won't match. +if LC_ALL=C grep -q -m 1 -i -e "^retry\\>" "/etc/security/pwquality.conf"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^retry\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf" +else + if [[ -s "/etc/security/pwquality.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/security/pwquality.conf" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/security/pwquality.conf" + fi + printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_password_pam_retry # promote to variable + set_fact: + var_password_pam_retry: !!str + tags: + - always + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Ensure retry is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bretry\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check if /etc/pam.d/system-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/system-auth + register: result_pam_file_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check the proper remediation for + the system + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/system-auth + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if system relies + on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect custom + profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check integrity of + authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Informative message + based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Get authselect current + profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the current + authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the new authselect + custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Get authselect current + features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if any custom + profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Create an authselect + custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure the authselect + custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Restore the authselect + features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Change the PAM file + to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure the "retry" option + from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect changes + are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check if /etc/pam.d/password-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check the proper remediation for + the system + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if system relies + on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect custom + profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check integrity of + authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Informative message + based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Get authselect current + profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the current + authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the new authselect + custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Get authselect current + features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if any custom + profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Create an authselect + custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Create an authselect + custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure the authselect + custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Restore the authselect + features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Change the PAM file + to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure the "retry" option + from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect changes + are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Ensure PAM variable retry is set + accordingly + ansible.builtin.lineinfile: + create: true + dest: /etc/security/pwquality.conf + regexp: ^#?\s*retry + line: retry = {{ var_password_pam_retry }} + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + Ensure PAM password complexity module is enabled in system-auth To enable PAM password complexity in system-auth file: Edit the password section in /etc/pam.d/system-auth to show password requisite pam_pwquality.so. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-001000 - SV-271611r1091545_rule + SRG-OS-000480-GPOS-00227 + OL09-00-001000 + SV-271611r1091545_rule Enabling PAM password complexity permits to enforce strong passwords and consequently makes the system less prone to dictionary attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then if [ -e "/etc/pam.d/system-auth" ] ; then PAM_FILE_PATH="/etc/pam.d/system-auth" @@ -31658,7 +37527,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001000 - accounts_password_pam_pwquality_system_auth @@ -31693,13 +37564,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM password complexity module is enabled in system-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -31744,6 +37616,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -31755,6 +37628,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM password complexity module is enabled in system-auth - Create @@ -31763,6 +37637,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -31772,6 +37647,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -31822,6 +37698,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -31900,7 +37778,8 @@ fi (result_pam_accounts_password_pam_pwquality_system_auth_add is defined and result_pam_accounts_password_pam_pwquality_system_auth_add.changed) or (result_pam_accounts_password_pam_pwquality_system_auth_edit is defined and result_pam_accounts_password_pam_pwquality_system_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001000 @@ -31926,7 +37805,8 @@ Edit the /etc/security/pwquality.conf to include retry= , or a lower value if site -policy is more restrictive. The DoD requirement is a maximum of 3 prompts +policy is more restrictive. The profile requirement is a maximum of retry= + prompts per session. 1 11 @@ -31947,7 +37827,6 @@ per session. DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -31998,42 +37877,22 @@ per session. PR.AC-6 PR.AC-7 PR.IP-1 - SRG-OS-000069-GPOS-00037 - SRG-OS-000480-GPOS-00227 + SRG-OS-000069-GPOS-00037 + SRG-OS-000480-GPOS-00227 R68 A.11.SEC-OL3 - OL09-00-001001 - SV-271612r1091548_rule Setting the password retry prompts that are permitted on a per-session basis to a low value requires some software, such as SSH, to re-connect. This can slow down and draw additional attention to some types of password-guessing attacks. Note that this is different from account lockout, which is provided by the pam_faillock module. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_retry='' -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^retry") -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_retry" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^retry\\>" "/etc/security/pwquality.conf"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^retry\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf" -else - if [[ -s "/etc/security/pwquality.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/security/pwquality.conf" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/security/pwquality.conf" - fi - printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf" -fi if [ -e "/etc/pam.d/password-auth" ] ; then PAM_FILE_PATH="/etc/pam.d/password-auth" @@ -32074,9 +37933,27 @@ fi authselect apply-changes -b fi -if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" -fi + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*" "$PAM_FILE_PATH"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwquality.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then + # The control is updated only if one single line matches. + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwquality.so.*)/\1requisite \2/" "$PAM_FILE_PATH" + else + LAST_MATCH_LINE=$(grep -nP "^\s*account" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwquality.so" "$PAM_FILE_PATH" + else + echo "password requisite pam_pwquality.so" >> "$PAM_FILE_PATH" + fi + fi + fi + # Check the option + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*\sretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwquality.so.*/ s/$/ retry=$var_password_pam_retry/" "$PAM_FILE_PATH" + else + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwquality.so\s+.*)(retry=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_retry \3/" "$PAM_FILE_PATH" + fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b @@ -32124,9 +38001,27 @@ fi authselect apply-changes -b fi -if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" -fi + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*" "$PAM_FILE_PATH"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwquality.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then + # The control is updated only if one single line matches. + sed -i -E --follow-symlinks "s/^(\s*password\s+).*(\bpam_pwquality.so.*)/\1requisite \2/" "$PAM_FILE_PATH" + else + LAST_MATCH_LINE=$(grep -nP "^\s*account" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwquality.so" "$PAM_FILE_PATH" + else + echo "password requisite pam_pwquality.so" >> "$PAM_FILE_PATH" + fi + fi + fi + # Check the option + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*\sretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwquality.so.*/ s/$/ retry=$var_password_pam_retry/" "$PAM_FILE_PATH" + else + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwquality.so\s+.*)(retry=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_retry \3/" "$PAM_FILE_PATH" + fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b @@ -32144,7 +38039,6 @@ fi manager: auto tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32160,35 +38054,39 @@ fi tags: - always -- name: Ensure PAM variable retry is set accordingly +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if expected PAM module line is present in /etc/pam.d/password-auth ansible.builtin.lineinfile: - create: true - dest: /etc/security/pwquality.conf - regexp: ^\s*retry - line: retry = {{ var_password_pam_retry }} - when: '"pam" in ansible_facts.packages' - tags: - - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - - NIST-800-53-AC-7(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(4) - - accounts_password_pam_retry - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check if /etc/pam.d/password-auth file is present - ansible.builtin.stat: path: /etc/pam.d/password-auth - register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32200,198 +38098,59 @@ fi - no_reboot_needed - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check the proper remediation for the system + Per-Session - Include or update the PAM module line in /etc/pam.d/password-auth block: - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the PAM file to be edited as a local fact - ansible.builtin.set_fact: - pam_file_path: /etc/pam.d/password-auth + Permitted Per-Session - Check if required PAM module line is present in /etc/pam.d/password-auth + with different control + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + regexp: ^\s*password\s+.*\s+pam_pwquality.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check if system relies on authselect tool - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect custom profile is used if authselect - is present - block: - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check integrity of authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - failed_when: false - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Informative message based on the authselect integrity - check result - ansible.builtin.assert: - that: - - result_authselect_check_cmd.rc == 0 - fail_msg: - - authselect integrity check failed. Remediation aborted! - - This remediation could not be applied because an authselect profile was - not selected or the selected profile is not intact. - - It is not recommended to manually edit the PAM files when authselect tool - is available. - - In cases where the default authselect profile does not cover a specific - demand, a custom authselect profile is recommended. - success_msg: - - authselect integrity check passed - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Get authselect current profile - ansible.builtin.shell: - cmd: authselect current -r | awk '{ print $1 }' - register: result_authselect_profile - changed_when: false - when: - - result_authselect_check_cmd is success - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the current authselect profile as a local fact - ansible.builtin.set_fact: - authselect_current_profile: '{{ result_authselect_profile.stdout }}' - authselect_custom_profile: '{{ result_authselect_profile.stdout }}' - when: - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the new authselect custom profile as a local - fact - ansible.builtin.set_fact: - authselect_current_profile: '{{ result_authselect_profile.stdout }}' - authselect_custom_profile: custom/hardening - when: - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Get authselect current features to also enable them - in the custom profile - ansible.builtin.shell: - cmd: authselect current | tail -n+3 | awk '{ print $2 }' - register: result_authselect_features - changed_when: false - when: - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check if any custom profile with the same name was - already created - ansible.builtin.stat: - path: /etc/authselect/{{ authselect_custom_profile }} - register: result_authselect_custom_profile_present - changed_when: false - when: - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Create an authselect custom profile based on the current - profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b {{ authselect_current_profile - }} - when: - - result_authselect_check_cmd is success - - authselect_current_profile is not match("^(custom/|local)") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Create an authselect custom profile based on sssd - profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b sssd - when: - - result_authselect_check_cmd is success - - authselect_current_profile is match("local") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=before-hardening-custom-profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure the authselect custom profile is selected - ansible.builtin.command: - cmd: authselect select {{ authselect_custom_profile }} - register: result_pam_authselect_select_profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Restore the authselect features in the custom profile - ansible.builtin.command: - cmd: authselect enable-feature {{ item }} - loop: '{{ result_authselect_features.stdout_lines }}' - register: result_pam_authselect_restore_features - when: - - result_authselect_profile is not skipped - - result_authselect_features is not skipped - - result_pam_authselect_select_profile is not skipped - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=after-hardening-custom-profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - result_pam_authselect_restore_features is not skipped - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Change the PAM file to be edited according to the - custom authselect profile - ansible.builtin.set_fact: - pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path - | basename }} - when: - - result_authselect_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define a fact for control already filtered in case filters - are used - ansible.builtin.set_fact: - pam_module_control: '' - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is - not present in {{ pam_file_path }} + Permitted Per-Session - Ensure the correct control for the required PAM module + line in /etc/pam.d/password-auth ansible.builtin.replace: - dest: '{{ pam_file_path }}' - regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) - replace: \1\2 - register: result_pam_option_removal + dest: /etc/pam.d/password-auth + regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*) + replace: \1{{ pam_module_control }} \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Ensure the required PAM module line is included in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + dest: /etc/pam.d/password-auth + insertafter: ^\s*account + line: password {{ pam_module_control }} pam_pwquality.so + register: result_pam_module_add + when: + - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found + > 1 - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - Ensure authselect changes are applied ansible.builtin.command: cmd: authselect apply-changes -b when: + - result_authselect_present is defined - result_authselect_present.stat.exists - - result_pam_option_removal is changed + - |- + (result_pam_module_add is defined and result_pam_module_add.changed) + or (result_pam_module_edit is defined and result_pam_module_edit.changed) when: - - '"pam" in ansible_facts.packages' - - result_pam_file_present.stat.exists + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32403,14 +38162,133 @@ fi - no_reboot_needed - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check if /etc/pam.d/system-auth file is present - ansible.builtin.stat: + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if the required PAM module option is present in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*\sretry\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_accounts_password_pam_retry_option_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the "retry" PAM option for "pam_pwquality.so" is included + in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so.*) + line: \1 retry={{ var_password_pam_retry }} + state: present + register: result_pam_accounts_password_pam_retry_add + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found is defined + - result_pam_module_accounts_password_pam_retry_option_present.found == 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the required value for "retry" PAM option from "pam_pwquality.so" + in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s+.*)(retry)=[0-9a-zA-Z]*\s*(.*) + line: \1\2={{ var_password_pam_retry }} \3 + register: result_pam_accounts_password_pam_retry_edit + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found > 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if expected PAM module line is present in /etc/pam.d/system-auth + ansible.builtin.lineinfile: path: /etc/pam.d/system-auth - register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32422,198 +38300,154 @@ fi - no_reboot_needed - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check the proper remediation for the system + Per-Session - Include or update the PAM module line in /etc/pam.d/system-auth block: - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the PAM file to be edited as a local fact - ansible.builtin.set_fact: - pam_file_path: /etc/pam.d/system-auth + Permitted Per-Session - Check if required PAM module line is present in /etc/pam.d/system-auth + with different control + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*password\s+.*\s+pam_pwquality.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check if system relies on authselect tool - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect custom profile is used if authselect - is present - block: - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check integrity of authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - failed_when: false - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Informative message based on the authselect integrity - check result - ansible.builtin.assert: - that: - - result_authselect_check_cmd.rc == 0 - fail_msg: - - authselect integrity check failed. Remediation aborted! - - This remediation could not be applied because an authselect profile was - not selected or the selected profile is not intact. - - It is not recommended to manually edit the PAM files when authselect tool - is available. - - In cases where the default authselect profile does not cover a specific - demand, a custom authselect profile is recommended. - success_msg: - - authselect integrity check passed - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Get authselect current profile - ansible.builtin.shell: - cmd: authselect current -r | awk '{ print $1 }' - register: result_authselect_profile - changed_when: false - when: - - result_authselect_check_cmd is success - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the current authselect profile as a local fact - ansible.builtin.set_fact: - authselect_current_profile: '{{ result_authselect_profile.stdout }}' - authselect_custom_profile: '{{ result_authselect_profile.stdout }}' - when: - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the new authselect custom profile as a local - fact - ansible.builtin.set_fact: - authselect_current_profile: '{{ result_authselect_profile.stdout }}' - authselect_custom_profile: custom/hardening - when: - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Get authselect current features to also enable them - in the custom profile - ansible.builtin.shell: - cmd: authselect current | tail -n+3 | awk '{ print $2 }' - register: result_authselect_features - changed_when: false - when: - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check if any custom profile with the same name was - already created - ansible.builtin.stat: - path: /etc/authselect/{{ authselect_custom_profile }} - register: result_authselect_custom_profile_present - changed_when: false - when: - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Create an authselect custom profile based on the current - profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b {{ authselect_current_profile - }} - when: - - result_authselect_check_cmd is success - - authselect_current_profile is not match("^(custom/|local)") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Create an authselect custom profile based on sssd - profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b sssd - when: - - result_authselect_check_cmd is success - - authselect_current_profile is match("local") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=before-hardening-custom-profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure the authselect custom profile is selected - ansible.builtin.command: - cmd: authselect select {{ authselect_custom_profile }} - register: result_pam_authselect_select_profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Restore the authselect features in the custom profile - ansible.builtin.command: - cmd: authselect enable-feature {{ item }} - loop: '{{ result_authselect_features.stdout_lines }}' - register: result_pam_authselect_restore_features - when: - - result_authselect_profile is not skipped - - result_authselect_features is not skipped - - result_pam_authselect_select_profile is not skipped - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=after-hardening-custom-profile - when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - result_pam_authselect_restore_features is not skipped - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Change the PAM file to be edited according to the - custom authselect profile - ansible.builtin.set_fact: - pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path - | basename }} - when: - - result_authselect_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define a fact for control already filtered in case filters - are used - ansible.builtin.set_fact: - pam_module_control: '' - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is - not present in {{ pam_file_path }} + Permitted Per-Session - Ensure the correct control for the required PAM module + line in /etc/pam.d/system-auth ansible.builtin.replace: - dest: '{{ pam_file_path }}' - regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) - replace: \1\2 - register: result_pam_option_removal + dest: /etc/pam.d/system-auth + regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*) + replace: \1{{ pam_module_control }} \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Ensure the required PAM module line is included in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + dest: /etc/pam.d/system-auth + insertafter: ^\s*account + line: password {{ pam_module_control }} pam_pwquality.so + register: result_pam_module_add + when: + - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found + > 1 - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - Ensure authselect changes are applied ansible.builtin.command: cmd: authselect apply-changes -b when: + - result_authselect_present is defined - result_authselect_present.stat.exists - - result_pam_option_removal is changed + - |- + (result_pam_module_add is defined and result_pam_module_add.changed) + or (result_pam_module_edit is defined and result_pam_module_edit.changed) when: - - '"pam" in ansible_facts.packages' - - result_pam_file_present.stat.exists + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if the required PAM module option is present in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*\sretry\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_accounts_password_pam_retry_option_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the "retry" PAM option for "pam_pwquality.so" is included + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so.*) + line: \1 retry={{ var_password_pam_retry }} + state: present + register: result_pam_accounts_password_pam_retry_add + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found is defined + - result_pam_module_accounts_password_pam_retry_option_present.found == 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the required value for "retry" PAM option from "pam_pwquality.so" + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s+.*)(retry)=[0-9a-zA-Z]*\s*(.*) + line: \1\2={{ var_password_pam_retry }} \3 + register: result_pam_accounts_password_pam_retry_edit + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found > 0 tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32650,7 +38484,6 @@ length credit for each uppercase character. Modify the ucreditDSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -32675,20 +38508,6 @@ length credit for each uppercase character. Modify the ucreditSR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -32708,11 +38527,24 @@ length credit for each uppercase character. Modify the ucreditPR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000069-GPOS-00037 - SRG-OS-000070-GPOS-00038 + SRG-OS-000069-GPOS-00037 + SRG-OS-000070-GPOS-00038 R31 - OL09-00-001005 - SV-271613r1091551_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-001005 + SV-271613r1091551_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -32721,14 +38553,18 @@ at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_ucredit='' +if grep -sq ucredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/ucredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -32780,6 +38616,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + if [ -f /usr/bin/authselect ]; then + + if ! authselect check; then + echo " + authselect integrity check failed. Remediation aborted! + This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact. + It is not recommended to manually edit the PAM files when authselect tool is available. + In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended." + exit 1 + fi + + CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }') + # If not already in use, a custom profile is created preserving the enabled features. + if [[ ! $CURRENT_PROFILE == custom/* ]]; then + ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }') + # The "local" profile does not contain essential security features required by multiple Benchmarks. + # If currently used, it is replaced by "sssd", which is the best option in this case. + if [[ $CURRENT_PROFILE == local ]]; then + CURRENT_PROFILE="sssd" + fi + authselect create-profile hardening -b $CURRENT_PROFILE + CURRENT_PROFILE="custom/hardening" + + authselect apply-changes -b --backup=before-hardening-custom-profile + authselect select $CURRENT_PROFILE + for feature in $ENABLED_FEATURES; do + authselect enable-feature $feature; + done + + authselect apply-changes -b --backup=after-hardening-custom-profile + fi + PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bucredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bucredit\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" +fi + if [ -f /usr/bin/authselect ]; then + + authselect apply-changes -b + fi +else + echo "/etc/pam.d/password-auth was not found" >&2 +fi @@ -32830,12 +38715,61 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Ensure ucredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bucredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) @@ -32875,13 +38809,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -32926,6 +38861,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -32937,6 +38873,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters @@ -32945,6 +38882,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -32954,6 +38892,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -33004,6 +38943,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -33012,6 +38953,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -33020,6 +38967,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bucredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Ensure authselect changes are applied @@ -33029,7 +38977,240 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + check_mode: false + failed_when: false + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Informative message based on the authselect integrity check result + ansible.builtin.assert: + that: + - ansible_check_mode or result_authselect_check_cmd.rc == 0 + fail_msg: + - authselect integrity check failed. Remediation aborted! + - This remediation could not be applied because an authselect profile was + not selected or the selected profile is not intact. + - It is not recommended to manually edit the PAM files when authselect tool + is available. + - In cases where the default authselect profile does not cover a specific + demand, a custom authselect profile is recommended. + success_msg: + - authselect integrity check passed + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Get authselect current profile + ansible.builtin.shell: + cmd: authselect current -r | awk '{ print $1 }' + register: result_authselect_profile + changed_when: false + when: + - result_authselect_check_cmd is success + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Define the current authselect profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: '{{ result_authselect_profile.stdout }}' + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Define the new authselect custom profile as a local fact + ansible.builtin.set_fact: + authselect_current_profile: '{{ result_authselect_profile.stdout }}' + authselect_custom_profile: custom/hardening + when: + - result_authselect_profile is not skipped + - result_authselect_profile.stdout is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Get authselect current features to also enable them in the custom profile + ansible.builtin.shell: + cmd: authselect current | tail -n+3 | awk '{ print $2 }' + register: result_authselect_features + changed_when: false + check_mode: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if any custom profile with the same name was already created + ansible.builtin.stat: + path: /etc/authselect/{{ authselect_custom_profile }} + register: result_authselect_custom_profile_present + changed_when: false + when: + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Create an authselect custom profile based on the current profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b {{ authselect_current_profile + }} + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is not match("^(custom/|local)") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Create an authselect custom profile based on sssd profile + ansible.builtin.command: + cmd: authselect create-profile hardening -b sssd + when: + - result_authselect_profile is not skipped + - result_authselect_check_cmd is success + - authselect_current_profile is match("local") + - not result_authselect_custom_profile_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=before-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure the authselect custom profile is selected + ansible.builtin.command: + cmd: authselect select {{ authselect_custom_profile }} + register: result_pam_authselect_select_profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - authselect_current_profile is not match("custom/") + - authselect_custom_profile is not match(authselect_current_profile) + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Restore the authselect features in the custom profile + ansible.builtin.command: + cmd: authselect enable-feature {{ item }} + loop: '{{ result_authselect_features.stdout_lines }}' + register: result_pam_authselect_restore_features + when: + - result_authselect_profile is not skipped + - result_authselect_features is not skipped + - result_pam_authselect_select_profile is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b --backup=after-hardening-custom-profile + when: + - result_authselect_check_cmd is success + - result_authselect_profile is not skipped + - result_pam_authselect_restore_features is not skipped + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Change the PAM file to be edited according to the custom authselect profile + ansible.builtin.set_fact: + pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path + | basename }} + when: + - authselect_custom_profile is defined + when: + - result_authselect_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bucredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001005 @@ -33052,7 +39233,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*ucredit line: ucredit = {{ var_password_pam_ucredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) @@ -33082,6 +39265,7 @@ fi The system's default algorithm for storing password hashes in /etc/shadow is SHA-512. This can be configured in several locations. + Minimum number of password hashing rounds configured through /etc/login.defs Minimum number of password hashing rounds configured through /etc/login.defs @@ -33110,7 +39294,6 @@ algorithm for password hashing: DSS06.03 DSS06.10 3.13.11 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -33135,9 +39318,6 @@ algorithm for password hashing: SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -33155,11 +39335,14 @@ algorithm for password hashing: PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 + 0418 + 1055 + 1402 8.3.2 8.3 - OL09-00-001050 - SV-271622r1091578_rule + OL09-00-001050 + SV-271622r1091578_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm @@ -33172,7 +39355,7 @@ configuration option in /etc/libuser.conf ensures the use algorithm that makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q libuser; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libuser; }; then var_password_hashing_algorithm_pam='' @@ -33227,7 +39410,9 @@ fi line: crypt_style = {{ var_password_hashing_algorithm_pam }} state: present create: true - when: '"libuser" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libuser" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001050 @@ -33273,7 +39458,6 @@ fi DSS06.03 DSS06.10 3.13.11 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -33298,9 +39482,6 @@ fi SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -33318,12 +39499,15 @@ fi PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 A.19.SEC-OL3 + 0418 + 1055 + 1402 8.3.2 8.3 - OL09-00-001055 - SV-271623r1091581_rule + OL09-00-001055 + SV-271623r1091581_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm @@ -33333,7 +39517,7 @@ are no more protected than if they are kept in plain text. Using a stronger hashing algorithm makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_password_hashing_algorithm='' @@ -33392,13 +39576,15 @@ fi - always - name: Set Password Hashing Algorithm in /etc/login.defs - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^#?ENCRYPT_METHOD line: ENCRYPT_METHOD {{ var_password_hashing_algorithm.split('|')[0] }} state: present create: true - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001055 @@ -33461,7 +39647,6 @@ option. DSS06.03 DSS06.10 3.13.11 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -33486,9 +39671,6 @@ option. SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -33506,11 +39688,14 @@ option. PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 A.19.SEC-OL3 - OL09-00-001060 - SV-271624r1091584_rule + 0418 + 1055 + 1402 + OL09-00-001060 + SV-271624r1091584_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm @@ -33523,7 +39708,7 @@ configuration option in /etc/libuser.conf ensures the use algorithm that makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_hashing_algorithm_pam='' @@ -33636,7 +39821,7 @@ for hash_option in "${HASHING_ALGORITHMS_OPTIONS[@]}"; do fi if grep -qP "^\s*password\s+.*\s+pam_unix.so\s.*\b$hash_option\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*password.*.*.*pam_unix.so.*)\s$hash_option=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(.*password.*.*.*pam_unix.so.*)\b$hash_option\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -33681,7 +39866,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001060 @@ -33722,13 +39909,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set PAM's Password Hashing Algorithm - password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -33773,6 +39961,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -33784,6 +39973,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect @@ -33792,6 +39982,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -33801,6 +39992,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -33851,6 +40043,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -33943,6 +40137,8 @@ fi state: present register: result_pam_set_password_hashing_algorithm_passwordauth_add when: + - result_pam_module_set_password_hashing_algorithm_passwordauth_option_present.found + is defined - result_pam_module_set_password_hashing_algorithm_passwordauth_option_present.found == 0 @@ -33956,6 +40152,7 @@ fi (result_pam_set_password_hashing_algorithm_passwordauth_add is defined and result_pam_set_password_hashing_algorithm_passwordauth_add.changed) or (result_pam_set_password_hashing_algorithm_passwordauth_edit is defined and result_pam_set_password_hashing_algorithm_passwordauth_edit.changed) when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: @@ -33978,7 +40175,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001060 @@ -34019,13 +40218,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set PAM's Password Hashing Algorithm - password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -34070,6 +40270,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -34081,6 +40282,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect @@ -34089,6 +40291,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -34098,6 +40301,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -34148,16 +40352,27 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists + - name: Set PAM's Password Hashing Algorithm - password-auth - Check if "{{ pam_file_path + }}" File is Present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: pam_file_path_present + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure That Only - the Correct Hashing Algorithm Option For pam_unix.so Is Used in /etc/pam.d/password-auth + the Correct Hashing Algorithm Option For pam_unix.so Is Used in {{ pam_file_path + }} ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: (^\s*password.*pam_unix\.so.*)\b{{ item }}\b\s*(.*) replace: \1\2 - when: item != var_password_hashing_algorithm_pam + when: + - item != var_password_hashing_algorithm_pam + - pam_file_path_present.stat.exists loop: - sha512 - yescrypt @@ -34176,6 +40391,7 @@ fi - result_authselect_present.stat.exists - result_pam_hashing_options_removal is changed when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: @@ -34238,9 +40454,6 @@ option. DSS06.03 DSS06.10 3.13.11 - CCI-000196 - CCI-000803 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -34265,9 +40478,6 @@ option. SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -34285,10 +40495,13 @@ option. PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 R68 A.19.SEC-OL3 + 0418 + 1055 + 1402 8.3.2 8.3 Passwords need to be protected at all times, and encryption is the standard method for @@ -34303,7 +40516,7 @@ configuration option in /etc/libuser.conf ensures the use algorithm that makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_hashing_algorithm_pam='' @@ -34311,6 +40524,63 @@ var_password_hashing_algorithm_pam='. - CCI-000803 - CCI-004062 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - OL09-00-001075 - SV-271627r1091593_rule - Passwords need to be protected at all times, and encryption is the standard -method for protecting passwords. If passwords are not encrypted, they can + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + OL09-00-001075 + SV-271627r1091593_rule + Passwords need to be protected at all times, and hashing is the standard +method for protecting passwords. If passwords are not hashed, they can be plainly read (i.e., clear text) and easily compromised. Passwords -that are encrypted with a weak algorithm are no more protected than if +that are hashed with a weak algorithm are no more protected than if they are kept in plain text. Using more hashing rounds makes password cracking attacks more difficult. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_password_hashing_min_rounds_login_defs='' -config_file="/etc/login.defs" +config_file=/etc/login.defs current_min_rounds=$(grep -Po '^\s*SHA_CRYPT_MIN_ROUNDS\s+\K\d+' "$config_file") current_max_rounds=$(grep -Po '^\s*SHA_CRYPT_MAX_ROUNDS\s+\K\d+' "$config_file") @@ -35046,8 +41287,23 @@ if [[ -n "$current_max_rounds" && "$current_max_rounds" -le "$var_passwo # Clean up after ourselves. rm "/etc/login.defs.bak" fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_password_hashing_min_rounds_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs +- name: XCCDF Value var_password_hashing_min_rounds_login_defs # promote to variable set_fact: var_password_hashing_min_rounds_login_defs: !!str tags: @@ -35058,6 +41314,7 @@ fi ansible.builtin.slurp: src: /etc/login.defs register: etc_login_defs + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35073,6 +41330,7 @@ fi etc_login_defs_sha_crypt_min_rounds: '{{ etc_login_defs[''content''] | b64decode | regex_search(''^\s*SHA_CRYPT_MIN_ROUNDS\s+(\d+)'', ''\1'', multiline=True) | default([], true) }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35088,6 +41346,7 @@ fi etc_login_defs_sha_crypt_max_rounds: '{{ etc_login_defs[''content''] | b64decode | regex_search(''^\s*SHA_CRYPT_MAX_ROUNDS\s+(\d+)'', ''\1'', multiline=True) | default([], true) }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35104,7 +41363,9 @@ fi regexp: (^\s*SHA_CRYPT_MIN_ROUNDS\s+)(?:\d+)(.*$) replace: \g<1>{{ var_password_hashing_min_rounds_login_defs }}\g<2> backup: false - when: etc_login_defs_sha_crypt_min_rounds is defined and etc_login_defs_sha_crypt_min_rounds + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_min_rounds is defined and etc_login_defs_sha_crypt_min_rounds | length > 0 and etc_login_defs_sha_crypt_min_rounds | first | int < var_password_hashing_min_rounds_login_defs | int tags: @@ -35123,7 +41384,9 @@ fi regexp: (^\s*SHA_CRYPT_MAX_ROUNDS\s+)(?:\d+)(.*$) replace: \g<1>{{ var_password_hashing_min_rounds_login_defs }}\g<2> backup: false - when: etc_login_defs_sha_crypt_max_rounds is defined and etc_login_defs_sha_crypt_max_rounds + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_max_rounds is defined and etc_login_defs_sha_crypt_max_rounds | length > 0 and etc_login_defs_sha_crypt_max_rounds | first | int < var_password_hashing_min_rounds_login_defs | int tags: @@ -35141,7 +41404,9 @@ fi line: SHA_CRYPT_MIN_ROUNDS {{ var_password_hashing_min_rounds_login_defs }} path: /etc/login.defs state: present - when: etc_login_defs_sha_crypt_min_rounds | length == 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_min_rounds | length == 0 tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35157,7 +41422,9 @@ fi line: SHA_CRYPT_MAX_ROUNDS {{ var_password_hashing_min_rounds_login_defs }} path: /etc/login.defs state: present - when: etc_login_defs_sha_crypt_max_rounds | length == 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_max_rounds | length == 0 tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35214,8 +41481,6 @@ The debug-shell service can be disabled with the followin $ sudo systemctl mask --now debug-shell.service 3.4.5 - CCI-000366 - CCI-002235 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35229,10 +41494,10 @@ The debug-shell service can be disabled with the followin 164.310(d)(2)(iii) CM-6 FIA_UAU.1 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - OL09-00-002403 - SV-271742r1091938_rule + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002403 + SV-271742r1091938_rule This prevents attackers with physical access from trivially bypassing security on the machine through valid troubleshooting configurations and gaining root access when the system is rebooted. @@ -35275,82 +41540,51 @@ fi - no_reboot_needed - service_debug-shell_disabled -- name: Disable debug-shell SystemD Service - Collect systemd Services Present in - the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable debug-shell SystemD Service - Disable service debug-shell + block: + + - name: Disable debug-shell SystemD Service - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable debug-shell SystemD Service - Ensure debug-shell.service is Masked + ansible.builtin.systemd: + name: debug-shell.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("debug-shell.service", multiline=True) + + - name: Unit Socket Exists - debug-shell.socket + ansible.builtin.command: systemctl -q list-unit-files debug-shell.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable debug-shell SystemD Service - Disable Socket debug-shell + ansible.builtin.systemd: + name: debug-shell.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("debug-shell.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002403 + - NIST-800-171-3.4.5 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_debug-shell_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled - -- name: Disable debug-shell SystemD Service - Ensure debug-shell.service is Masked - ansible.builtin.systemd: - name: debug-shell.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("debug-shell.service", multiline=True) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled - -- name: Unit Socket Exists - debug-shell.socket - ansible.builtin.command: systemctl -q list-unit-files debug-shell.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled - -- name: Disable debug-shell SystemD Service - Disable Socket debug-shell - ansible.builtin.systemd: - name: debug-shell.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("debug-shell.socket", multiline=True) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled include disable_debug-shell @@ -35365,6 +41599,10 @@ class disable_debug-shell { [customizations.services] masked = ["debug-shell"] + + + + @@ -35401,8 +41639,6 @@ the non-graphical runlevel 3. DSS05.07 DSS06.02 3.4.5 - CCI-000366 - CCI-002235 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35440,25 +41676,25 @@ the non-graphical runlevel 3. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) CM-6(a) PR.AC-4 PR.DS-5 FAU_GEN.1.2 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - OL09-00-002412 - SV-271751r1091965_rule + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002412 + SV-271751r1091965_rule A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term @@ -35508,7 +41744,7 @@ fi - no_reboot_needed - name: Disable Ctrl-Alt-Del Burst Action - lineinfile: + ansible.builtin.lineinfile: dest: /etc/systemd/system.conf state: present regexp: ^CtrlAltDelBurstAction @@ -35566,8 +41802,6 @@ as this file may be restored during future system updates.DSS05.07 DSS06.02 3.4.5 - CCI-000366 - CCI-002235 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35605,24 +41839,24 @@ as this file may be restored during future system updates.A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 FAU_GEN.1.2 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - OL09-00-002413 - SV-271752r1091968_rule + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002413 + SV-271752r1091968_rule A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term @@ -35630,7 +41864,7 @@ loss of availability of systems due to unintentional reboot.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then systemctl disable ctrl-alt-del.target systemctl mask ctrl-alt-del.target else @@ -35658,7 +41892,7 @@ fi - no_reboot_needed - name: Disable Ctrl-Alt-Del Reboot Activation - systemd: + ansible.builtin.systemd: name: ctrl-alt-del.target force: true masked: true @@ -35715,7 +41949,6 @@ It is also required to change the runtime configuration, run: DSS06.06 3.1.2 3.4.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35782,9 +42015,9 @@ It is also required to change the runtime configuration, run: PR.AC-4 PR.AC-6 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002392 - SV-271736r1091920_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002392 + SV-271736r1091920_rule Using interactive or recovery boot, the console user could disable auditing, firewalls, or other services, weakening system security. @@ -35838,12 +42071,13 @@ fi - reboot_required - restrict_strategy -- name: Verify GRUB_DISABLE_RECOVERY=true - lineinfile: +- name: Verify that Interactive Boot is Disabled - Verify GRUB_DISABLE_RECOVERY=true + ansible.builtin.lineinfile: path: /etc/default/grub regexp: ^GRUB_DISABLE_RECOVERY=.* line: GRUB_DISABLE_RECOVERY=true state: present + register: grub_disable_recovery_changed when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -35860,11 +42094,13 @@ fi - reboot_required - restrict_strategy -- name: Verify that Interactive Boot is Disabled in /etc/default/grub - replace: +- name: Verify that Interactive Boot is Disabled - Verify that Interactive Boot is + Disabled in /etc/default/grub + ansible.builtin.replace: dest: /etc/default/grub regexp: systemd.confirm_spawn(=(1|yes|true|on)|\b) replace: systemd.confirm_spawn=no + register: grub_confirm_spawn_changed when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -35881,11 +42117,13 @@ fi - reboot_required - restrict_strategy -- name: Verify that Interactive Boot is Disabled (runtime) - command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn" +- name: Verify that Interactive Boot is Disabled - Verify that Interactive Boot is + Disabled (runtime) + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn" when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' + - grub_confirm_spawn_changed is changed tags: - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 @@ -35899,11 +42137,13 @@ fi - reboot_required - restrict_strategy -- name: Regen grub.cfg handle updated GRUB_DISABLE_RECOVERY and confirm_spawn - command: grub2-mkconfig -o /boot/grub2/grub.cfg +- name: Verify that Interactive Boot is Disabled - Regen grub.cfg handle updated GRUB_DISABLE_RECOVERY + and confirm_spawn + ansible.builtin.command: grub2-mkconfig -o /boot/grub2/grub.cfg when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' + - grub_disable_recovery_changed is changed or grub_confirm_spawn_changed is changed tags: - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 @@ -35957,7 +42197,6 @@ after DSS06.03 DSS06.10 3.1.11 - CCI-001133 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -36006,12 +42245,12 @@ after A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 CM-6(a) AC-17(a) AC-2(5) @@ -36028,7 +42267,7 @@ after PR.IP-2 FMT_SMF_EXT.1.1 Req-8.1.8 - SRG-OS-000163-GPOS-00072 + SRG-OS-000163-GPOS-00072 R32 Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management @@ -36089,7 +42328,7 @@ fi - name: Set 'StopIdleSessionSec' to '{{ var_logind_session_timeout }}' in the [Login] section of '/etc/systemd/logind.conf' - ini_file: + community.general.ini_file: path: /etc/systemd/logind.conf section: Login option: StopIdleSessionSec @@ -36156,7 +42395,6 @@ in /usr/lib/systemd/system/emergency.service.DSS06.10 3.1.1 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -36210,20 +42448,6 @@ in /usr/lib/systemd/system/emergency.service.SR 2.5 SR 2.6 SR 2.7 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.6.1.2 A.7.1.1 @@ -36247,26 +42471,38 @@ in /usr/lib/systemd/system/emergency.service.PR.AC-6 PR.AC-7 PR.PT-3 - SRG-OS-000080-GPOS-00048 - OL09-00-000025 - SV-271441r1091035_rule + SRG-OS-000080-GPOS-00048 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-000025 + SV-271441r1117265_rule This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented by configuring the bootloader password. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -service_file="/usr/lib/systemd/system/emergency.service" +service_dropin_cfg_dir="/etc/systemd/system/emergency.service.d" +service_dropin_file="${service_dropin_cfg_dir}/10-oscap.conf" sulogin="/usr/lib/systemd/systemd-sulogin-shell emergency" -if grep "^ExecStart=.*" "$service_file" ; then - sed -i "s%^ExecStart=.*%ExecStart=-$sulogin%" "$service_file" -else - echo "ExecStart=-$sulogin" >> "$service_file" -fi +mkdir -p "${service_dropin_cfg_dir}" +echo "[Service]" >> "${service_dropin_file}" +echo "ExecStart=-$sulogin" >> "${service_dropin_file}" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -36290,11 +42526,12 @@ fi - restrict_strategy - name: Require emergency mode password - lineinfile: + ansible.builtin.blockinfile: create: true - dest: /usr/lib/systemd/system/emergency.service - regexp: ^#?ExecStart= - line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + dest: /etc/systemd/system/emergency.service.d/10-oscap.conf + block: |- + [Service] + ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000025 @@ -36345,7 +42582,6 @@ in /usr/lib/systemd/system/rescue.service.DSS06.10 3.1.1 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -36399,20 +42635,6 @@ in /usr/lib/systemd/system/rescue.service.SR 2.5 SR 2.6 SR 2.7 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.6.1.2 A.7.1.1 @@ -36428,16 +42650,16 @@ in /usr/lib/systemd/system/rescue.service.A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 AC-3 CM-6(a) @@ -36447,9 +42669,22 @@ in /usr/lib/systemd/system/rescue.service.PR.AC-7 PR.PT-3 FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - OL09-00-000030 - SV-271442r1091038_rule + SRG-OS-000080-GPOS-00048 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-000030 + SV-271442r1117265_rule This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented by configuring the bootloader password. @@ -36466,10 +42701,13 @@ for f in $(echo -n "/etc/systemd/system/rescue.service.d/10-oscap.conf /etc/syst # find key in section and change value if grep -qzosP "[[:space:]]*\[Service\]([^\n\[]*\n+)+?[[:space:]]*ExecStart" "$f"; then + if ! grep -qPz "ExecStart=\nExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue" "$f"; then sed -i "s/ExecStart[^(\n)]*/ExecStart=\nExecStart=-\/usr\/lib\/systemd\/systemd-sulogin-shell rescue/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[Service\]" "$f"; then @@ -36510,12 +42748,84 @@ fi - require_singleuser_auth - restrict_strategy -- name: Require Authentication for Single User Mode - Require single user mode password - lineinfile: - create: true - dest: /usr/lib/systemd/system/rescue.service - regexp: ^#?ExecStart= - line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue +- name: Require Authentication for Single User Mode - find files which already override + Execstart of rescue.service + ansible.builtin.find: + paths: /etc/systemd/system/rescue.service.d + patterns: '*.conf' + contains: ^\s*ExecStart=.*$ + register: rescue_service_overrides_found + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + +- name: Require Authentication for Single User Mode - set files containing ExecStart + overrides as target + ansible.builtin.set_fact: + rescue_service_remediation_target_file: '{{ rescue_service_overrides_found.files + | map(attribute=''path'') | list }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rescue_service_overrides_found.matched is defined and rescue_service_overrides_found.matched + > 0 + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + +- name: Require Authentication for Single User Mode - set default target for rescue.service + override + ansible.builtin.set_fact: + rescue_service_remediation_target_file: + - /etc/systemd/system/rescue.service.d/10-oscap.conf + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rescue_service_overrides_found.matched is defined and rescue_service_overrides_found.matched + == 0 + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + +- name: Require Authentication for Single User Mode - Require emergency user mode + password + community.general.ini_file: + path: '{{ item }}' + section: Service + option: ExecStart + values: + - '' + - -/usr/lib/systemd/systemd-sulogin-shell rescue + loop: '{{ rescue_service_remediation_target_file }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000030 @@ -36611,16 +42921,12 @@ The opensc package can be installed with the following co $ sudo yum install opensc - CCI-001953 - CCI-004046 - 1382 - 1384 - 1386 CM-6(a) - SRG-OS-000375-GPOS-00160 - SRG-OS-000376-GPOS-00161 - OL09-00-000400 - SV-271515r1091257_rule + SRG-OS-000375-GPOS-00160 + SRG-OS-000376-GPOS-00161 + 1386 + OL09-00-000400 + SV-271515r1091257_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -36629,9 +42935,8 @@ authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -36657,7 +42962,7 @@ fi - package_opensc_installed - name: Ensure opensc is installed - package: + ansible.builtin.package: name: opensc state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -36700,14 +43005,11 @@ version = "*" $ sudo yum install pcsc-lite - CCI-004046 - 1382 - 1384 - 1386 CM-6(a) - SRG-OS-000375-GPOS-00160 - OL09-00-000390 - SV-271514r1091254_rule + SRG-OS-000375-GPOS-00160 + 1386 + OL09-00-000390 + SV-271514r1091254_rule The pcsc-lite package must be installed if it is to be available for multifactor authentication using smartcards. # Remediation is applicable only in certain platforms @@ -36735,7 +43037,7 @@ fi - package_pcsc-lite_installed - name: Ensure pcsc-lite is installed - package: + ansible.builtin.package: name: pcsc-lite state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -36781,18 +43083,14 @@ The openssl-pkcs11 package can be installed with the foll $ sudo yum install openssl-pkcs11 - CCI-000765 - CCI-001953 - CCI-001954 - CCI-004046 CM-6(a) Req-8.3 - SRG-OS-000105-GPOS-00052 - SRG-OS-000375-GPOS-00160 - SRG-OS-000375-GPOS-00161 - SRG-OS-000377-GPOS-00162 - OL09-00-000270 - SV-271491r1091185_rule + SRG-OS-000105-GPOS-00052 + SRG-OS-000375-GPOS-00160 + SRG-OS-000375-GPOS-00161 + SRG-OS-000377-GPOS-00162 + OL09-00-000270 + SV-271491r1091185_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -36801,9 +43099,8 @@ authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ); }; then @@ -36831,7 +43128,7 @@ fi - no_reboot_needed - name: Ensure openssl-pkcs11 is installed - package: + ansible.builtin.package: name: openssl-pkcs11 state: present when: @@ -36877,10 +43174,6 @@ version = "*" The pcscd service can be enabled with the following command: $ sudo systemctl enable pcscd.service - CCI-004046 - 1382 - 1384 - 1386 IA-2(1) IA-2(2) IA-2(3) @@ -36890,9 +43183,10 @@ The pcscd service can be enabled with the following comma IA-2(11) CM-6(a) Req-8.3 - SRG-OS-000375-GPOS-00160 - OL09-00-000401 - SV-271516r1091260_rule + SRG-OS-000375-GPOS-00160 + 1386 + OL09-00-000401 + SV-271516r1091260_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -36901,9 +43195,8 @@ authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -36939,27 +43232,21 @@ fi - no_reboot_needed - service_pcscd_enabled -- name: Enable service pcscd +- name: Enable the pcscd Service - Enable service pcscd block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - - name: Start service pcscd - systemd: + - name: Enable the pcscd Service - Enable Service pcscd + ansible.builtin.systemd: name: pcscd + enabled: true state: started - masked: 'no' + masked: false when: - '"pcsc-lite" in ansible_facts.packages' - - - name: Enable service pcscd - ansible.builtin.command: - cmd: systemctl enable pcscd - when: - - '"pcsc-lite" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000401 - NIST-800-53-CM-6(a) @@ -36977,6 +43264,8 @@ fi - medium_severity - no_reboot_needed - service_pcscd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_pcscd @@ -36991,6 +43280,10 @@ class enable_pcscd { [customizations.services] enabled = ["pcscd"] + + + + @@ -37026,11 +43319,6 @@ app default { DSS05.10 DSS06.03 DSS06.10 - CCI-001941 - CCI-004045 - CCI-000765 - CCI-000766 - CCI-000764 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -37055,9 +43343,6 @@ app default { SR 1.8 SR 1.9 SR 2.1 - 1382 - 1384 - 1386 A.18.1.4 A.7.1.1 A.9.2.1 @@ -37080,15 +43365,16 @@ app default { PR.AC-6 PR.AC-7 Req-8.3 - SRG-OS-000104-GPOS-00051 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000109-GPOS-00056 - SRG-OS-000108-GPOS-00055 - SRG-OS-000108-GPOS-00057 - SRG-OS-000108-GPOS-00058 - OL09-00-000940 - SV-271610r1091542_rule + SRG-OS-000104-GPOS-00051 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000109-GPOS-00056 + SRG-OS-000108-GPOS-00055 + SRG-OS-000108-GPOS-00057 + SRG-OS-000108-GPOS-00058 + 1386 + OL09-00-000940 + SV-271610r1091542_rule Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials. @@ -37137,7 +43423,7 @@ fi - always - name: Check existence of opensc conf - stat: + ansible.builtin.stat: path: /etc/opensc-{{ ansible_architecture }}.conf register: opensc_conf_cd when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -37163,12 +43449,12 @@ fi block: - name: Check if card_drivers is defined - command: /usr/bin/opensc-tool -G app:default:card_drivers + ansible.builtin.command: /usr/bin/opensc-tool -G app:default:card_drivers changed_when: false register: card_drivers - name: Configure opensc Smart Card Drivers - command: | + ansible.builtin.command: | /usr/bin/opensc-tool -S app:default:card_drivers:{{ var_smartcard_drivers }} when: - card_drivers.stdout != var_smartcard_drivers @@ -37218,7 +43504,7 @@ operationally necessary. Accounts Authorized Local Users on the Operating System List the user accounts that are authorized locally on the operating system. This list -includes both users requried by the operating system and by the installed applications. +includes both users required by the operating system and by the installed applications. Depending on the Operating System distribution, version, software groups and applications, the user list is different and can be customized with scap-workbench. OVAL regular expression is used for the user list. @@ -37236,6 +43522,7 @@ in OVAL that is always allowed on the operating system. ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc)$ ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty)$ ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty|salt|cockpit-ws|cockpit-wsinstance)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty|salt|cockpit-ws|cockpit-wsinstance)$ ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|tss|systemd-coredump|dbus|polkitd|avahi|colord|rtkit|pipewire|clevis|sssd|geoclue|flatpak|setroubleshoot|libstoragemgmt|systemd-oom|gdm|cockpit-ws|cockpit-wsinstance|gnome-initial-setup|sshd|chrony|dnsmasq|tcpdump|admin)$ @@ -37243,16 +43530,13 @@ in OVAL that is always allowed on the operating system. Change user IDs (UIDs), or delete accounts, so each has a unique name. Automatic remediation of this control is not available due to unique requirements of each system. - CCI-000135 - CCI-000764 - CCI-000804 Req-8.1.1 - SRG-OS-000104-GPOS-00051 - SRG-OS-000121-GPOS-00062 + SRG-OS-000104-GPOS-00051 + SRG-OS-000121-GPOS-00062 8.2.1 8.2 - OL09-00-003001 - SV-271832r1092208_rule + OL09-00-003001 + SV-271832r1092208_rule To assure accountability and prevent unauthenticated access, interactive users must be identified and authenticated to prevent potential misuse and compromise of the system. @@ -37279,14 +43563,14 @@ To remove unauthorized system accounts, use the following command: Automatic remediation of this control is not available due to the unique requirements of each system. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002501 - SV-271770r1092022_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002501 + SV-271770r1092022_rule Accounts providing no operational purpose provide additional opportunities for system compromise. Unnecessary accounts include user accounts for individuals not requiring access to the system and application accounts for applications not installed on the system. + @@ -37299,13 +43583,13 @@ on the system. Ensure All Groups on the System Have Unique Group ID Change the group name or delete groups, so each has a unique id. Automatic remediation of this control is not available due to the unique requirements of each system. - CCI-000764 - SRG-OS-000104-GPOS-00051 + SRG-OS-000104-GPOS-00051 8.2.1 8.2 - OL09-00-003006 - SV-271835r1092217_rule + OL09-00-003006 + SV-271835r1092217_rule To assure accountability and prevent unauthenticated access, groups must be identified uniquely to prevent potential misuse and compromise of the system. + @@ -37331,6 +43615,7 @@ The file /etc/default/useradd controls default settings for all newly-created accounts created with the system's normal command line utilities. This will only apply to newly created accounts + number of days after the last login of the user when the user will be locked out 'This option is specific for the auth or account phase. It specifies the number of days after @@ -37373,15 +43658,14 @@ will also use authselect tool. However, if any manual mod PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. - CCI-000795 IA-4(e) - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then PAM_FILE_PATH="/etc/pam.d/password-auth" if [ -f /usr/bin/authselect ]; then @@ -37432,7 +43716,7 @@ fi if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*\sinactive\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_lastlog.so.*/ s/$/ inactive=35/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]+\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]*\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" fi if ! grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then @@ -37468,7 +43752,7 @@ else fi - + @@ -37491,15 +43775,14 @@ will also use authselect tool. However, if any manual mod PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. - CCI-000795 IA-4(e) - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then PAM_FILE_PATH="/etc/pam.d/system-auth" if [ -f /usr/bin/authselect ]; then @@ -37550,7 +43833,7 @@ fi if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*\sinactive\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_lastlog.so.*/ s/$/ inactive=35/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]+\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]*\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" fi if ! grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then @@ -37586,7 +43869,7 @@ else fi - + @@ -37628,8 +43911,6 @@ elapse until the account would be automatically disabled. See the DSS06.03 DSS06.10 3.5.6 - CCI-003628 - CCI-003627 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -37673,14 +43954,14 @@ elapse until the account would be automatically disabled. See the A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 IA-4(e) AC-2(3) CM-6(a) @@ -37691,17 +43972,17 @@ elapse until the account would be automatically disabled. See the PR.AC-6 PR.AC-7 Req-8.1.4 - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 8.2.6 8.2 - OL09-00-003065 - SV-271849r1092259_rule + OL09-00-003065 + SV-271849r1092259_rule Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Disabling inactive accounts ensures that accounts which may not have been responsibly removed are not available to attackers who may have compromised their credentials. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_account_disable_post_pw_expiration='' @@ -37756,12 +44037,14 @@ fi - always - name: Set Account Expiration Following Inactivity - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/default/useradd regexp: ^INACTIVE line: INACTIVE={{ var_account_disable_post_pw_expiration }} - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - DISA-STIG-OL09-00-003065 @@ -37818,8 +44101,6 @@ period of 72 hours. DSS05.05 DSS05.07 DSS06.03 - CCI-000016 - CCI-001682 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -37860,10 +44141,10 @@ period of 72 hours. PR.AC-1 PR.AC-4 PR.AC-6 - SRG-OS-000123-GPOS-00064 - SRG-OS-000002-GPOS-00002 - OL09-00-003030 - SV-271843r1094969_rule + SRG-OS-000123-GPOS-00064 + SRG-OS-000002-GPOS-00002 + OL09-00-003030 + SV-271843r1094969_rule If temporary user accounts remain active when no longer needed or for an excessive period, these accounts may be used to gain unauthorized access. To mitigate this risk, automated termination of all temporary accounts @@ -37882,8 +44163,6 @@ To ensure all accounts have unique names, run the following command: $ sudo getent passwd | awk -F: '{ print $1}' | uniq -d If a username is returned, change or delete the username. 5.5.2 - CCI-000770 - CCI-000804 Req-8.1.1 8.2.1 8.2 @@ -37946,6 +44225,7 @@ could be adjusted to a 180 day maximum password age, 7 day minimum password age, and 7 day warning period with the following command: $ sudo chage -M 180 -m 7 -W 7 USER + maximum password age Maximum age of password in days @@ -38008,8 +44288,6 @@ edit the file /etc/login.defs and add or correct the following line: PASS_MAX_DAYS -A value of 180 days is sufficient for many environments. -The DoD requirement is 60. The profile requirement is . 1 12 @@ -38024,7 +44302,6 @@ The profile requirement is DSS06.03 DSS06.10 3.5.6 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -38049,9 +44326,6 @@ The profile requirement is SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -38069,12 +44343,15 @@ The profile requirement is PR.AC-6 PR.AC-7 Req-8.2.4 - SRG-OS-000076-GPOS-00044 + SRG-OS-000076-GPOS-00044 A.5.SEC-OL5 + 0418 + 1055 + 1402 8.3.9 8.3 - OL09-00-001095 - SV-271631r1091605_rule + OL09-00-001095 + SV-271631r1091605_rule Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the @@ -38087,7 +44364,7 @@ increases the risk of users writing down the password in a convenient location subject to physical compromise. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_maximum_age_login_defs='' @@ -38141,12 +44418,14 @@ fi - always - name: Set Password Maximum Age - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/login.defs regexp: ^#?PASS_MAX_DAYS line: PASS_MAX_DAYS {{ var_accounts_maximum_age_login_defs }} - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1 - DISA-STIG-OL09-00-001095 @@ -38180,7 +44459,7 @@ and add or correct the following line: PASS_MIN_DAYS A value of 1 day is considered sufficient for many -environments. The DoD requirement is 1. +environments. The profile requirement is . 1 12 @@ -38195,7 +44474,6 @@ The profile requirement is DSS06.03 DSS06.10 3.5.8 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -38220,9 +44498,6 @@ The profile requirement is SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -38239,8 +44514,13 @@ The profile requirement is PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000075-GPOS-00043 + SRG-OS-000075-GPOS-00043 A.5.SEC-OL5 + 0418 + 1055 + 1402 + OL09-00-001085 + SV-271629r1091599_rule Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, @@ -38252,7 +44532,7 @@ Setting the minimum password age protects against users cycling back to a favorite password after satisfying the password reuse requirement. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_minimum_age_login_defs='' @@ -38285,6 +44565,7 @@ fi manager: auto tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001085 - NIST-800-171-3.5.8 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38302,14 +44583,17 @@ fi - always - name: Set Password Minimum Age - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/login.defs regexp: ^#?PASS_MIN_DAYS line: PASS_MIN_DAYS {{ var_accounts_minimum_age_login_defs }} - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001085 - NIST-800-171-3.5.8 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38337,8 +44621,6 @@ fi -The DoD requirement is 15. -The FISMA requirement is 12. The profile requirement is . If a program consults /etc/login.defs and also another PAM module @@ -38358,7 +44640,6 @@ information about enforcing password quality requirements.DSS06.03 DSS06.10 3.5.7 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -38383,20 +44664,6 @@ information about enforcing password quality requirements.SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -38413,10 +44680,21 @@ information about enforcing password quality requirements.PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000078-GPOS-00046 + SRG-OS-000078-GPOS-00046 R31 - OL09-00-001105 - SV-271633r1091611_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 Requiring a minimum password length makes password cracking attacks more difficult by ensuring a larger search space. However, any security benefit from an onerous requirement @@ -38424,7 +44702,7 @@ must be carefully weighed against usability problems, support costs, or counterp behavior that may result. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_password_minlen_login_defs='' @@ -38457,7 +44735,6 @@ fi manager: auto tags: - CJIS-5.6.2.1 - - DISA-STIG-OL09-00-001105 - NIST-800-171-3.5.7 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) @@ -38475,16 +44752,17 @@ fi - always - name: Set Password Minimum Length in login.defs - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^PASS_MIN_LEN *[0-9]* state: present line: PASS_MIN_LEN {{ var_accounts_password_minlen_login_defs }} create: true - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1 - - DISA-STIG-OL09-00-001105 - NIST-800-171-3.5.7 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) @@ -38512,22 +44790,23 @@ restriction by running the following command: USER - CCI-004066 IA-5(f) IA-5(1)(d) CM-6(a) - SRG-OS-000076-GPOS-00044 + SRG-OS-000076-GPOS-00044 A.5.SEC-OL5 8.3.9 8.3 - OL09-00-001100 - SV-271632r1091608_rule + OL09-00-001100 + SV-271632r1091608_rule Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_maximum_age_login_defs='' @@ -38536,8 +44815,28 @@ while IFS= read -r i; do chage -M $var_accounts_maximum_age_login_defs $i done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($5 > var || $5 == "")) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001100 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_max_life_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable set_fact: var_accounts_maximum_age_login_defs: !!str tags: @@ -38548,6 +44847,9 @@ done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+ cmd: awk -F':' '(/^[^:]+:[^!*]/ && ($5 > {{ var_accounts_maximum_age_login_defs }} || $5 == "")) {print $1}' /etc/shadow register: user_names + changed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001100 - NIST-800-53-CM-6(a) @@ -38567,7 +44869,9 @@ done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+ user: '{{ item }}' password_expire_max: '{{ var_accounts_maximum_age_login_defs }}' with_items: '{{ user_names.stdout_lines }}' - when: user_names.stdout_lines | length > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - user_names.stdout_lines | length > 0 tags: - DISA-STIG-OL09-00-001100 - NIST-800-53-CM-6(a) @@ -38617,22 +44921,21 @@ lifetime by running the following command: $ sudo chage -m 1 USER - CCI-004066 IA-5(f) IA-5(1)(d) CM-6(a) - SRG-OS-000075-GPOS-00043 + SRG-OS-000075-GPOS-00043 A.5.SEC-OL5 - OL09-00-001090 - OL09-00-001085 - SV-271630r1091602_rule - SV-271629r1091599_rule + OL09-00-001090 + SV-271630r1091602_rule Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_minimum_age_login_defs='' @@ -38641,19 +44944,39 @@ while IFS= read -r i; do chage -m $var_accounts_minimum_age_login_defs $i done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($4 < var || $4 == "")) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001090 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - accounts_password_set_min_life_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable set_fact: var_accounts_minimum_age_login_defs: !!str tags: - always - name: Collect users with not correct minimum time period between password changes - command: | + ansible.builtin.command: | awk -F':' '(/^[^:]+:[^!*]/ && ($4 < {{ var_accounts_minimum_age_login_defs }} || $4 == "")) {print $1}' /etc/shadow register: user_names + changed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-001085 - DISA-STIG-OL09-00-001090 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38666,12 +44989,13 @@ done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+ - restrict_strategy - name: Change the minimum time period between password changes - command: | + ansible.builtin.command: | chage -m {{ var_accounts_minimum_age_login_defs }} {{ item }} with_items: '{{ user_names.stdout_lines }}' - when: user_names.stdout_lines | length > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - user_names.stdout_lines | length > 0 tags: - - DISA-STIG-OL09-00-001085 - DISA-STIG-OL09-00-001090 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38699,9 +45023,7 @@ users, run the command: $ sudo chage --warndays USER -The DoD requirement is 7, and CIS recommendation is no less than 7 days. This profile requirement is . - CCI-000198 IA-5(f) IA-5(1)(d) CM-6(a) @@ -38711,15 +45033,36 @@ This profile requirement is + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_password_warn_age_login_defs='' while IFS= read -r i; do chage --warndays $var_accounts_password_warn_age_login_defs $i done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(($6 < var || $6 == "") && $2 ~ /^\$/) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_warn_age_existing + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable set_fact: var_accounts_password_warn_age_login_defs: !!str tags: @@ -38732,6 +45075,7 @@ done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(( "") && $2 ~ /^\$/) {print $1}' /etc/shadow register: result_pass_warn_age_user_names changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38751,7 +45095,9 @@ done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(( cmd: chage --warndays {{ var_accounts_password_warn_age_login_defs }} {{ item }} with_items: '{{ result_pass_warn_age_user_names.stdout_lines }}' - when: result_pass_warn_age_user_names is not skipped and result_pass_warn_age_user_names.stdout_lines + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_pass_warn_age_user_names is not skipped and result_pass_warn_age_user_names.stdout_lines | length > 0 tags: - NIST-800-53-CM-6(a) @@ -38782,7 +45128,6 @@ edit the file /etc/login.defs and add or correct the following line: PASS_WARN_AGE -The DoD requirement is 7. The profile requirement is . 1 12 @@ -38830,9 +45175,6 @@ The profile requirement is SR 1.9 SR 2.1 SR 6.2 - 0418 - 1055 - 1402 A.12.4.1 A.12.4.3 A.18.1.4 @@ -38861,13 +45203,16 @@ The profile requirement is PR.AC-7 Req-8.2.4 A.5.SEC-OL5 + 0418 + 1055 + 1402 8.3.9 8.3 Setting the password warning age enables users to make the change at a practical time. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_password_warn_age_login_defs='' @@ -38919,13 +45264,15 @@ fi - always - name: Set Password Warning Age - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^PASS_WARN_AGE *[0-9]* state: present line: PASS_WARN_AGE {{ var_accounts_password_warn_age_login_defs }} create: true - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - NIST-800-171-3.5.8 - NIST-800-53-CM-6(a) @@ -38953,8 +45300,7 @@ fi Set existing passwords a period of inactivity before they been locked Configure user accounts that have been inactive for over a given period of time to be automatically disabled by running the following command: -$ sudo chage --inactive 30USER - +$ sudo chage --inactive 30 USER DSS01.03 DSS03.05 @@ -38965,10 +45311,6 @@ to be automatically disabled by running the following command: DSS06.03 DSS06.10 3.5.6 - CCI-000017 - CCI-000795 - CCI-003627 - CCI-003628 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -39012,14 +45354,14 @@ to be automatically disabled by running the following command: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 IA-4(e) AC-2(3) CM-6(a) @@ -39030,20 +45372,43 @@ to be automatically disabled by running the following command: PR.AC-6 PR.AC-7 Req-8.1.4 - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 8.2.6 8.2 Inactive accounts pose a threat to system security since the users are not logging in to notice failed login attempts or other anomalies. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_account_disable_post_pw_expiration='' while IFS= read -r i; do chage --inactive $var_account_disable_post_pw_expiration $i done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 > var || $7 == "") && $2 ~ /^\$/) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.5.6 + - NIST-800-53-AC-2(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-4(e) + - PCI-DSS-Req-8.1.4 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.6 + - accounts_set_post_pw_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable set_fact: var_account_disable_post_pw_expiration: !!str tags: @@ -39055,6 +45420,7 @@ done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 && $2 ~ /^\$/) {print $1}' /etc/shadow register: user_names changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.5.6 - NIST-800-53-AC-2(3) @@ -39074,7 +45440,9 @@ done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 ansible.builtin.command: cmd: chage --inactive {{ var_account_disable_post_pw_expiration }} {{ item }} with_items: '{{ user_names.stdout_lines }}' - when: user_names is not skipped and user_names.stdout_lines | length > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - user_names is not skipped and user_names.stdout_lines | length > 0 tags: - NIST-800-171-3.5.6 - NIST-800-53-AC-2(3) @@ -39169,7 +45537,6 @@ properly stored, or the account should be deleted entirely.SR 1.8 SR 1.9 SR 2.1 - 1410 A.18.1.4 A.7.1.1 A.9.2.1 @@ -39186,6 +45553,7 @@ properly stored, or the account should be deleted entirely.PR.AC-6 PR.AC-7 Req-8.2.1 + 1402 8.3.2 8.3 The hashes for all user account passwords should be stored in @@ -39212,16 +45580,14 @@ Password hashes ! or * indicate in available for logon and are not evaluated. If any interactive user password hash does not begin with $6, this is a finding. - CCI-000803 - CCI-004062 IA-5(1)(c) IA-5(1).1(v) IA-7 IA-7.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - OL09-00-001080 - SV-271628r1091596_rule + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + OL09-00-001080 + SV-271628r1091596_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. @@ -39264,16 +45630,14 @@ to the pam_unix.so entry, as shown below: The system's default number of rounds is 5000. Setting a high number of hashing rounds makes it more difficult to brute force the password, but requires more CPU resources to authenticate users. - CCI-000803 - CCI-004062 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 R68 - OL09-00-001065 - SV-271625r1091587_rule + OL09-00-001065 + SV-271625r1091587_rule Using a higher number of rounds makes password cracking attacks more difficult. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_password_pam_unix_rounds='' @@ -39332,7 +45696,7 @@ if [ -e "/etc/pam.d/password-auth" ] ; then if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ rounds=$var_password_pam_unix_rounds/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -39368,7 +45732,8 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-001065 - accounts_password_pam_unix_rounds_password_auth @@ -39403,13 +45768,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set number of Password Hashing Rounds - password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -39454,6 +45820,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -39465,6 +45832,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set number of Password Hashing Rounds - password-auth - Create an authselect @@ -39473,6 +45841,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -39482,6 +45851,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -39532,6 +45902,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -39623,6 +45995,8 @@ fi state: present register: result_pam_accounts_password_pam_unix_rounds_password_auth_add when: + - result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found == 0 @@ -39631,7 +46005,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_unix_rounds }} \3 register: result_pam_accounts_password_pam_unix_rounds_password_auth_edit when: @@ -39648,7 +46022,8 @@ fi (result_pam_accounts_password_pam_unix_rounds_password_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_add.changed) or (result_pam_accounts_password_pam_unix_rounds_password_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001065 @@ -39681,16 +46056,14 @@ to the pam_unix.so entry, as shown below: The system's default number of rounds is 5000. Setting a high number of hashing rounds makes it more difficult to brute force the password, but requires more CPU resources to authenticate users. - CCI-000803 - CCI-004062 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 R68 - OL09-00-001070 - SV-271626r1091590_rule + OL09-00-001070 + SV-271626r1091590_rule Using a higher number of rounds makes password cracking attacks more difficult. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_password_pam_unix_rounds='' @@ -39748,7 +46121,7 @@ if [ -e "/etc/pam.d/system-auth" ] ; then if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ rounds=$var_password_pam_unix_rounds/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -39784,7 +46157,8 @@ fi ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-001070 - accounts_password_pam_unix_rounds_system_auth @@ -39819,13 +46193,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set number of Password Hashing Rounds - system-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was @@ -39870,6 +46245,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") @@ -39881,6 +46257,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set number of Password Hashing Rounds - system-auth - Create an authselect @@ -39889,6 +46266,7 @@ fi cmd: authselect create-profile hardening -b {{ authselect_current_profile }} when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is not match("^(custom/|local)") - not result_authselect_custom_profile_present.stat.exists @@ -39898,6 +46276,7 @@ fi ansible.builtin.command: cmd: authselect create-profile hardening -b sssd when: + - result_authselect_profile is not skipped - result_authselect_check_cmd is success - authselect_current_profile is match("local") - not result_authselect_custom_profile_present.stat.exists @@ -39948,6 +46327,8 @@ fi ansible.builtin.set_fact: pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path | basename }} + when: + - authselect_custom_profile is defined when: - result_authselect_present.stat.exists @@ -40039,6 +46420,8 @@ fi state: present register: result_pam_accounts_password_pam_unix_rounds_system_auth_add when: + - result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found == 0 @@ -40047,7 +46430,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_unix_rounds }} \3 register: result_pam_accounts_password_pam_unix_rounds_system_auth_edit when: @@ -40064,7 +46447,8 @@ fi (result_pam_accounts_password_pam_unix_rounds_system_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_add.changed) or (result_pam_accounts_password_pam_unix_rounds_system_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001070 @@ -40098,7 +46482,6 @@ fi DSS05.10 DSS06.03 DSS06.10 - CCI-000764 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -40133,27 +46516,27 @@ fi A.9.3.1 A.9.4.2 A.9.4.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 CM-6(a) PR.AC-1 PR.AC-6 PR.AC-7 Req-8.5.a - SRG-OS-000104-GPOS-00051 + SRG-OS-000104-GPOS-00051 8.2.2 8.2 - OL09-00-003005 - SV-271834r1092214_rule + OL09-00-003005 + SV-271834r1092214_rule If a user is assigned the Group Identifier (GID) of a group not existing on the system, and a group with the Group Identifier (GID) is subsequently created, the user may have unintended rights to any files associated with the group. @@ -40204,7 +46587,6 @@ a container anyway. DSS06.10 3.1.1 3.1.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -40283,11 +46665,12 @@ a container anyway. PR.DS-5 FIA_UAU.1 Req-8.2.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1546 8.3.1 8.3 - OL09-00-001110 - SV-271634r1091614_rule + OL09-00-001110 + SV-271634r1091614_rule If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with empty passwords should never be used in operational environments. @@ -40310,19 +46693,19 @@ authselect apply-changes -b else if grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" + sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" fi if grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" + sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" fi if grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/password-auth"; then - sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" + sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" fi if grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/password-auth"; then - sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" + sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" fi fi @@ -40384,13 +46767,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Prevent Login to Accounts With Empty Password - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -40407,6 +46791,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -40517,15 +46902,14 @@ Lock an account: $ sudo passwd -l [username] Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into a container anyway. - CCI-000366 CM-6(b) CM-6.1(iv) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.6.SEC-OL4 2.2.2 2.2 - OL09-00-001130 - SV-271638r1091626_rule + OL09-00-001130 + SV-271638r1091626_rule If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with empty passwords should never be used in operational environments. @@ -40561,7 +46945,7 @@ fi - restrict_strategy - name: Collect users with no password - command: | + ansible.builtin.command: | awk -F: '!$2 {print $1}' /etc/shadow register: users_nopasswd changed_when: false @@ -40580,7 +46964,7 @@ fi - restrict_strategy - name: Lock users with no password - command: | + ansible.builtin.command: | passwd -l {{ item }} with_items: '{{ users_nopasswd.stdout_lines }}' when: @@ -40630,7 +47014,6 @@ users and should not be used. Any .netrc files should be DSS06.03 DSS06.06 DSS06.10 - CCI-000196 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -40688,21 +47071,21 @@ users and should not be used. Any .netrc files should be A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R1.3 - CIP-003-8 R3 - CIP-003-8 R3.1 - CIP-003-8 R3.2 - CIP-003-8 R3.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R1.3 + CIP-003-8 R3 + CIP-003-8 R3.1 + CIP-003-8 R3.2 + CIP-003-8 R3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-5(h) IA-5(1)(c) CM-6(a) @@ -40714,6 +47097,7 @@ users and should not be used. Any .netrc files should be PR.PT-3 Unencrypted passwords for remote FTP servers may be stored in .netrc files. + @@ -40780,7 +47164,6 @@ assigned. DSS06.10 3.1.1 3.1.5 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -40838,16 +47221,16 @@ assigned. A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 AC-6(5) IA-4(b) @@ -40857,22 +47240,52 @@ assigned. PR.AC-7 PR.DS-5 Req-8.5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1546 8.2.1 8.2 - OL09-00-003000 - SV-271831r1092205_rule + OL09-00-003000 + SV-271831r1092205_rule An account has root authority if it has a UID of 0. Multiple accounts with a UID of 0 afford more opportunity for potential intruders to guess a password for a privileged account. Proper configuration of sudo is recommended to afford multiple system administrators access to root privileges in an accountable manner. - awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all /etc/passwd file entries - getent: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003000 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-6(5) + - NIST-800-53-IA-2 + - NIST-800-53-IA-4(b) + - PCI-DSS-Req-8.5 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.1 + - accounts_no_uid_except_zero + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Get all /etc/passwd file entries + ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003000 - NIST-800-171-3.1.1 @@ -40891,10 +47304,12 @@ access to root privileges in an accountable manner. - restrict_strategy - name: Lock the password of the user accounts other than root with uid 0 - command: passwd -l {{ item.key }} + ansible.builtin.command: passwd -l {{ item.key }} loop: '{{ getent_passwd | dict2items | rejectattr(''key'', ''search'', ''root'') | list }}' - when: item.value.1 == '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value.1 == '0' tags: - DISA-STIG-OL09-00-003000 - NIST-800-171-3.1.1 @@ -40926,6 +47341,7 @@ access to root privileges in an accountable manner. 8.2.1 8.2 To help ensure that root-owned files are not inadvertently exposed to other users. + @@ -40948,7 +47364,7 @@ accomplished by use_pam_wheel_group_for_su rule.The su program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting access to such command is considered a good security practice. - + @@ -41053,16 +47469,16 @@ the pam_securetty.so PAM module is properly enabled in re A.9.3.1 A.9.4.2 A.9.4.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 CM-6(a) PR.AC-1 @@ -41103,7 +47519,7 @@ fi - restrict_strategy - name: Direct root Logins Not Allowed - copy: + ansible.builtin.copy: dest: /etc/securetty content: '' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -41140,15 +47556,15 @@ and nfsnobody has an unlocked password, disable it with t $ sudo usermod -L account - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6 CM-6(a) A.6.SEC-OL3 @@ -41156,7 +47572,10 @@ and nfsnobody has an unlocked password, disable it with t 8.2 Disabling authentication for default system accounts makes it more difficult for attackers to make use of them to compromise a system. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + readarray -t systemaccounts < <(awk -F: \ '($3 < 1000 && $3 != root && $3 != halt && $3 != sync && $3 != shutdown \ && $3 != nfsnobody) { print $1 }' /etc/passwd) @@ -41164,11 +47583,31 @@ readarray -t systemaccounts < <(awk -F: \ for systemaccount in "${systemaccounts[@]}"; do usermod -L "$systemaccount" done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure that System Accounts Are Locked - Get All Local Users From /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 + - low_complexity + - medium_disruption + - medium_severity + - no_password_auth_for_systemaccounts + - no_reboot_needed + - restrict_strategy + +- name: Ensure that System Accounts Are Locked - Get All Local Users From /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) @@ -41185,6 +47624,7 @@ done getent_passwd Facts ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd | dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) @@ -41203,6 +47643,7 @@ done password_lock: true loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int < 1000 - item.key not in ['root', 'halt', 'sync', 'shutdown', 'nfsnobody'] tags: @@ -41257,7 +47698,6 @@ system to become inaccessible. DSS05.05 DSS05.07 DSS06.03 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -41274,7 +47714,6 @@ system to become inaccessible. SR 1.9 SR 2.1 SR 6.2 - 1491 A.12.4.1 A.12.4.3 A.6.1.2 @@ -41300,15 +47739,19 @@ system to become inaccessible. PR.AC-1 PR.AC-4 PR.AC-6 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.6.SEC-OL3 + 1491 8.2.2 8.2 - OL09-00-003051 - SV-271845r1092247_rule + OL09-00-003051 + SV-271845r1092247_rule Ensuring shells are not given to system accounts upon login makes it more difficult for attackers to make use of system accounts. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != root \ && $7 != "\/sbin\/shutdown" && $7 != "\/sbin\/halt" && $7 != "\/bin\/sync") \ { print $1 }' /etc/passwd) @@ -41316,12 +47759,35 @@ readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != ro for systemaccount in "${systemaccounts[@]}"; do usermod -s /sbin/nologin "$systemaccount" done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure that System Accounts Do Not Run a Shell Upon Login - Get All Local + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003051 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - no_shelllogin_for_systemaccounts + - restrict_strategy + +- name: Ensure that System Accounts Do Not Run a Shell Upon Login - Get All Local Users From /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 @@ -41341,6 +47807,7 @@ done Variable From getent_passwd Facts ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd | dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 @@ -41363,6 +47830,7 @@ done shell: /sbin/nologin loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.key not in ['root'] - item.value[1]|int < 1000 - item.value[5] not in ['/sbin/shutdown', '/sbin/halt', '/bin/sync'] @@ -41409,7 +47877,6 @@ ttyS1 DSS06.02 3.1.1 3.1.5 - CCI-000770 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -41447,15 +47914,15 @@ ttyS1 A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6 CM-6(a) PR.AC-4 @@ -41463,13 +47930,37 @@ ttyS1 Preventing direct root login to serial port interfaces helps ensure accountability for actions taken on the systems using the root account. - sed -i '/ttyS/d' /etc/securetty + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sed -i '/ttyS/d' /etc/securetty + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Restrict Serial Port Root Logins - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_serial_port_logins + - restrict_strategy + +- name: Restrict Serial Port Root Logins + ansible.builtin.lineinfile: dest: /etc/securetty regexp: ttyS[0-9] state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 @@ -41512,7 +48003,6 @@ vc/4 DSS06.02 3.1.1 3.1.5 - CCI-000770 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -41550,32 +48040,58 @@ vc/4 A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6 CM-6(a) PR.AC-4 PR.DS-5 - SRG-OS-000324-GPOS-00125 + SRG-OS-000324-GPOS-00125 8.6.1 8.6 Preventing direct root login to virtual console devices helps ensure accountability for actions taken on the system using the root account. - sed -i '/^vc\/[0-9]/d' /etc/securetty + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sed -i '/^vc\/[0-9]/d' /etc/securetty + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Restrict Virtual Console Root Logins - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.6 + - PCI-DSSv4-8.6.1 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - securetty_root_login_console_only + +- name: Restrict Virtual Console Root Logins + ansible.builtin.lineinfile: dest: /etc/securetty regexp: ^vc/[0-9] state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 @@ -41607,14 +48123,12 @@ sure that the following line exists in the file /etc/pam.d/suMembers of "wheel" or GID 0 groups are checked by default if the group option is not set for pam_wheel.so module. Therefore, members of these groups should be manually checked or a different group should be informed according to the site policy. - CCI-002165 - CCI-004895 FMT_SMF_EXT.1.1 - SRG-OS-000373-GPOS-00156 - SRG-OS-000312-GPOS-00123 + SRG-OS-000373-GPOS-00156 + SRG-OS-000312-GPOS-00123 A.5.SEC-OL1 - OL09-00-002361 - SV-271723r1091881_rule + OL09-00-002361 + SV-271723r1091881_rule The su program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting access to such command is considered a good security practice. @@ -41642,7 +48156,7 @@ fi - use_pam_wheel_for_su - name: Restrict usage of su command only to members of wheel group - replace: + ansible.builtin.replace: path: /etc/pam.d/su regexp: ^[\s]*#[\s]*auth[\s]+required[\s]+pam_wheel\.so[\s]+use_uid$ replace: auth required pam_wheel.so use_uid @@ -41752,15 +48266,14 @@ parameter in /etc/login.defs to yes CREATE_HOME yes - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003052 - SV-271846r1092250_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003052 + SV-271846r1092250_rule If local interactive users are not assigned a valid home directory, there is no place for the storage and control of files they should own. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if ( rpm --quiet -q shadow-utils && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if [ -e "/etc/login.defs" ] ; then @@ -41806,7 +48319,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/login.defs create: true regexp: (?i)^\s*CREATE_HOME\s+ @@ -41816,7 +48329,7 @@ fi register: dupes - name: Deduplicate values from /etc/login.defs - lineinfile: + ansible.builtin.lineinfile: path: /etc/login.defs create: true regexp: (?i)^\s*CREATE_HOME\s+ @@ -41824,13 +48337,14 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/login.defs - lineinfile: + ansible.builtin.lineinfile: path: /etc/login.defs create: true regexp: (?i)^\s*CREATE_HOME\s+ line: CREATE_HOME yes state: present - when: '"shadow-utils" in ansible_facts.packages' + when: ( "shadow-utils" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-003052 - accounts_have_homedir_login_defs @@ -41861,7 +48375,6 @@ add or correct the FAIL_DELAY setting in /etc/ BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -41874,14 +48387,14 @@ add or correct the FAIL_DELAY setting in /etc/ AC-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00226 - OL09-00-003070 - SV-271850r1092262_rule + SRG-OS-000480-GPOS-00226 + OL09-00-003070 + SV-271850r1092262_rule Increasing the time between a failed authentication attempt and re-prompting to enter credentials helps to slow a single-threaded brute force attack. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if ( rpm --quiet -q shadow-utils && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_accounts_fail_delay='' @@ -41930,12 +48443,13 @@ fi - always - name: Set accounts logon fail delay - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^FAIL_DELAY line: FAIL_DELAY {{ var_accounts_fail_delay }} create: true - when: '"shadow-utils" in ansible_facts.packages' + when: ( "shadow-utils" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-003070 - NIST-800-53-AC-7(b) @@ -41972,7 +48486,6 @@ a file under /etc/security/limits.d/: 5.5.2.2 DSS01.05 DSS05.02 - CCI-000054 4.3.3.4 SR 3.1 SR 3.8 @@ -41981,20 +48494,20 @@ a file under /etc/security/limits.d/: A.13.2.1 A.14.1.2 A.14.1.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 AC-10 CM-6(a) PR.AC-5 - SRG-OS-000027-GPOS-00008 - OL09-00-002415 - SV-271753r1091971_rule + SRG-OS-000027-GPOS-00008 + OL09-00-002415 + SV-271753r1091971_rule Limiting simultaneous user logins can insulate the system from denial of service problems caused by excessive logins. Automated login processes operating improperly or maliciously may result in an exceptional number of simultaneous login sessions. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_accounts_max_concurrent_login_sessions='' @@ -42032,12 +48545,13 @@ fi - always - name: Find /etc/security/limits.d files containing maxlogins configuration - find: + ansible.builtin.find: paths: /etc/security/limits.d contains: ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins patterns: '*.conf' register: maxlogins - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2.2 - DISA-STIG-OL09-00-002415 @@ -42052,14 +48566,15 @@ fi - name: Limit the Number of Concurrent Login Sessions Allowed Per User in files from limits.d - replace: + ansible.builtin.replace: dest: '{{ item.path }}' regexp: ^#?\*.*maxlogins.* replace: '* hard maxlogins {{ var_accounts_max_concurrent_login_sessions }}' with_items: - '{{ maxlogins.files }}' - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2.2 - DISA-STIG-OL09-00-002415 @@ -42073,7 +48588,7 @@ fi - restrict_strategy - name: Limit the Number of Concurrent Login Sessions Allowed Per User - lineinfile: + ansible.builtin.lineinfile: state: present dest: /etc/security/limits.conf insertbefore: ^# End of file @@ -42082,7 +48597,8 @@ fi }}' create: true when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - maxlogins.matched == 0 tags: - CJIS-5.5.2.2 @@ -42116,7 +48632,10 @@ Then, add the following entry to /etc/security/namespace.confPolyinstantiation of temporary directories is a proactive security measure which reduces chances of attacks that are made possible by /tmp directories being world-writable. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + # shellcheck disable=SC2174 mkdir -p --mode 000 /tmp/tmp-inst chmod 000 /tmp/tmp-inst @@ -42128,6 +48647,10 @@ if ! grep -Eq '^\s*/tmp\s+/tmp/tmp-inst/\s+level\s+root,adm$' /etc/security/name fi echo "/tmp /tmp/tmp-inst/ level root,adm" >> /etc/security/namespace.conf fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi @@ -42148,7 +48671,10 @@ Then, add the following entry to /etc/security/namespace.confPolyinstantiation of temporary directories is a proactive security measure which reduces chances of attacks that are made possible by /var/tmp directories being world-writable. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + # shellcheck disable=SC2174 mkdir -p --mode 000 /var/tmp/tmp-inst chmod 000 /var/tmp/tmp-inst @@ -42160,6 +48686,10 @@ if ! grep -Eq '^\s*/var/tmp\s+/var/tmp/tmp-inst/\s+level\s+root,adm$' /etc/secur fi echo "/var/tmp /var/tmp/tmp-inst/ level root,adm" >> /etc/security/namespace.conf fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi @@ -42171,8 +48701,9 @@ fi Set Interactive Session Timeout Setting the TMOUT option in /etc/profile ensures that -all user sessions will terminate based on inactivity. -The value of TMOUT should be exported and read only. +all user sessions will terminate based on inactivity. A value of 0 (zero) +disables the automatic logout feature and is therefore not a compliant setting. +The value of TMOUT should be a positive integer, exported, and read only. The TMOUT setting in a file loaded by /etc/profile, e.g. @@ -42191,8 +48722,6 @@ Using the typeset keyword is preferred for wider compatib DSS05.10 DSS06.10 3.1.11 - CCI-000057 - CCI-001133 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -42215,25 +48744,25 @@ Using the typeset keyword is preferred for wider compatib A.9.3.1 A.9.4.2 A.9.4.3 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-12 SC-10 AC-2(5) CM-6(a) PR.AC-7 - SRG-OS-000163-GPOS-00072 - SRG-OS-000029-GPOS-00010 + SRG-OS-000163-GPOS-00072 + SRG-OS-000029-GPOS-00010 R32 A.5.SEC-OL8 8.6.1 8.6 - OL09-00-002411 - SV-271750r1091962_rule + OL09-00-002411 + SV-271750r1091962_rule Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been @@ -42245,7 +48774,7 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_accounts_tmout='' -# if 0, no occurence of tmout found, if 1, occurence found +# if 0, no occurrence of tmout found, if 1, occurrence found tmout_found=0 @@ -42291,7 +48820,7 @@ fi - always - name: Correct any occurrence of TMOUT in /etc/profile - replace: + ansible.builtin.replace: path: /etc/profile regexp: ^[^#].*TMOUT=.* replace: typeset -xr TMOUT={{ var_accounts_tmout }} @@ -42314,7 +48843,7 @@ fi - restrict_strategy - name: Set Interactive Session Timeout - lineinfile: + ansible.builtin.lineinfile: path: /etc/profile.d/tmout.sh create: true regexp: TMOUT= @@ -42358,20 +48887,99 @@ is group-owned by an interactive user. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of their respective initialization files. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 Local initialization files for interactive users are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon. - -awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") }' /etc/passwd + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +awk -F: '{if ($4 >= 1000 && $4 != 65534) print $4":"$6}' /etc/passwd | while IFS=: read -r gid home; do find -P "$home" -maxdepth 1 -type f -name "\.[^.]*" -exec chgrp -f --no-dereference -- $gid "{}" \;; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure interactive local users are the group-owners of their respective initialization - files - ansible.builtin.command: - cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") - }' /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Get interactive + users from passwd file + ansible.builtin.getent: + database: passwd + register: passwd_entries + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Create + list of interactive users with GID and home directory + ansible.builtin.set_fact: + interactive_users: '{{ interactive_users | default([]) + [{''home'': item.value[4], + ''gid'': item.value[2]}] }}' + loop: '{{ passwd_entries.ansible_facts.getent_passwd | dict2items }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[2] | int >= 1000 | int + - item.value[2] | int != 65534 | int + - item.value[4] != "" + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Find + dot files in interactive user home directories + ansible.builtin.find: + paths: '{{ item.home }}' + patterns: .* + file_type: file + hidden: true + depth: 1 + follow: false + register: user_dotfiles + loop: '{{ interactive_users | default([]) }}' + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.home != "" + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Set correct + group ownership for user initialization files + ansible.builtin.file: + path: '{{ item.1.path }}' + group: '{{ item.0.item.gid }}' + follow: false + loop: '{{ user_dotfiles.results | subelements(''files'', skip_missing=True) }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.0 is not skipped + - item.1.path is defined tags: - accounts_user_dot_group_ownership - low_complexity @@ -42394,16 +49002,18 @@ following command: $ sudo chmod o-w FILE - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002427 - SV-271765r1092007_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002427 + SV-271765r1092007_rule If user start-up files execute world-writable programs, especially in unprotected directories, they could be maliciously modified to destroy user files or otherwise compromise the system at the user level. If the system is compromised at the user level, it is easier to elevate privileges to eventually compromise the system at the root and network level. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + readarray -t world_writable_files < <(find / -xdev -type f -perm -0002 2> /dev/null) readarray -t interactive_home_dirs < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd) @@ -42415,12 +49025,29 @@ for world_writable in "${world_writable_files[@]}"; do fi done done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: User Initialization Files Must Not Run World-Writable Programs - Initialize + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Initialize variables - set_fact: + ansible.builtin.set_fact: home_user_dirs: [] world_writable_files: [] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42435,6 +49062,7 @@ done ansible.builtin.getent: database: passwd register: passwd_database + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42445,10 +49073,11 @@ done - restrict_strategy - name: User Initialization Files Must Not Run World-Writable Programs - Fill home_user_dirs - set_fact: + ansible.builtin.set_fact: home_user_dirs: '{{ home_user_dirs + [item.data[4]] }}' - when: item.data[4] is defined and item.data[2]|int >= 1000 and item.data[2]|int - != 65534 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.data[4] is defined and item.data[2]|int >= 1000 and item.data[2]|int != 65534 with_items: '{{ passwd_database.ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' tags: @@ -42465,6 +49094,9 @@ done ansible.builtin.shell: | find / -xdev -type f -perm -0002 2> /dev/null register: world_writable_files + changed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42484,6 +49116,7 @@ done recurse: true with_items: '{{ world_writable_files.stdout_lines }}' register: referenced_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42498,7 +49131,9 @@ done ansible.builtin.file: path: '{{ item.item }}' mode: o-w - when: item.matched > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.matched > 0 with_items: '{{ referenced_files.results }}' tags: - DISA-STIG-OL09-00-002427 @@ -42528,20 +49163,102 @@ is owned by an interactive user. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the ownership of their respective initialization files. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 Local initialization files are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon. - -awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$6"/.[^\.]?*") }' /etc/passwd + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +awk -F: '{if ($3 >= 1000 && $3 != 65534) print $3":"$6}' /etc/passwd | while IFS=: read -r uid home; do find -P "$home" -maxdepth 1 -type f -name "\.[^.]*" -exec chown -f --no-dereference -- $uid "{}" \;; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure interactive local users are the owners of their respective initialization - files - ansible.builtin.command: - cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$6"/.[^\.]?*") - }' /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Get interactive + users from passwd file + ansible.builtin.getent: + database: passwd + register: passwd_entries + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Create list + of interactive users with UID and home directory + ansible.builtin.set_fact: + interactive_users: '{{ interactive_users | default([]) + [{''uid'': item.value[1], + ''home'': item.value[4], ''username'': item.key}] }}' + loop: '{{ passwd_entries.ansible_facts.getent_passwd | dict2items }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[1] | int >= 1000 | int + - item.value[1] | int != 65534 | int + - item.value[4] != "" + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Find dot files + in interactive user home directories + ansible.builtin.find: + paths: '{{ item.home }}' + patterns: .* + file_type: file + hidden: true + depth: 1 + follow: false + register: user_dotfiles + loop: '{{ interactive_users | default([]) }}' + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.home != "" + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Set correct + ownership for user initialization files + ansible.builtin.file: + path: '{{ item.1.path }}' + owner: '{{ item.0.item.username }}' + follow: false + loop: '{{ user_dotfiles.results | subelements(''files'', skip_missing=True) }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.0 is not skipped + - item.0 is not failed + - item.0.item is defined + - item.0.item.username is defined + - item.1.path is defined tags: - accounts_user_dot_user_ownership - low_complexity @@ -42562,10 +49279,9 @@ awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$ Ensure that all interactive user initialization files executable search path statements do not contain statements that will reference a working directory other than the users home directory. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003053 - SV-271847r1092253_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003053 + SV-271847r1092253_rule The executable search path (typically the PATH environment variable) contains a list of directories for the shell to search to find executables. If this path includes the current working directory (other than the users home directory), @@ -42575,6 +49291,7 @@ an empty entry, such as a leading or trailing colon or two consecutive colons, this is interpreted as the current working directory. If deviations from the default system search path for the local interactive user are required, they must be documented with the Information System Security Officer (ISSO). + @@ -42588,24 +49305,43 @@ This rule checks if the home directory is properly defined in a folder which has at least one parent folder, like "user" in "/home/user" or "/remote/users/user". Therefore, this rule will report a finding for home directories like /users, /tmp or /. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003002 - SV-271833r1092607_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003002 + SV-271833r1092607_rule If local interactive users are not assigned a valid home directory, there is no place for the storage and control of files they should own. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1 }' /etc/passwd); do # This follows the same logic of evaluation of home directories as used in OVAL. if ! grep -q $user /etc/passwd | cut -d: -f6 | grep '^\/\w*\/\w\{1,\}'; then sed -i "s/\($user:x:[0-9]*:[0-9]*:.*:\).*\(:.*\)$/\1\/home\/$user\2/g" /etc/passwd; fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003002 + - accounts_user_interactive_home_directory_defined + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined @@ -42618,6 +49354,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined @@ -42634,6 +49371,7 @@ done create_home: false loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[2]|int >= 1000 - item.value[2]|int != 65534 - item.value[2]|int < 61184 or item.value[2]|int > 65519 @@ -42662,24 +49400,43 @@ home directory assigned in /etc/passwd: $ sudo mkdir /home/USER - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003050 - SV-271844r1092244_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003050 + SV-271844r1092244_rule If a local interactive user has a home directory defined that does not exist, the user may be given access to the / directory as the current working directory upon logon. This could create a Denial of Service because the user would not be able to access their logon configuration files, and it may give them visibility to system files they normally would not be able to access. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1}' /etc/passwd); do mkhomedir_helper $user 0077; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003050 + - accounts_user_interactive_home_directory_exists + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists @@ -42692,6 +49449,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists @@ -42707,8 +49465,9 @@ done create_home: true loop: '{{ local_users }}' when: - - item.value[2]|int >= 1000 - - item.value[2]|int != 65534 + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[1]|int >= 1000 + - item.value[1]|int != 65534 tags: - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists @@ -42738,12 +49497,14 @@ to an interactive user is group-owned by an interactive user.Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of folders or files in their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 If a local interactive users files are group-owned by a group of which the user is not a member, unintended users may be able to access them. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $1 }' /etc/passwd); do home_dir=$(getent passwd $user | cut -d: -f6) group=$(getent passwd $user | cut -d: -f4) @@ -42752,11 +49513,27 @@ for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $ # check systems that also check inodes timestamps. find $home_dir -not -group $group -exec chgrp -f --no-dereference $group {} \; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_users_home_files_groupownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_groupownership - low_complexity @@ -42768,6 +49545,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_groupownership - low_complexity @@ -42783,6 +49561,7 @@ done register: path_exists loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int >= 1000 - item.value[1]|int != 65534 - item.value[4] != "/" @@ -42800,7 +49579,9 @@ done group: '{{ item.0.value[2] }}' recurse: true loop: '{{ local_users|zip(path_exists.results)|list }}' - when: item.1.stat is defined and item.1.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.1.stat is defined and item.1.stat.exists tags: - accounts_users_home_files_groupownership - low_complexity @@ -42830,13 +49611,15 @@ to an interactive user is owned by an interactive user. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the ownership of folders or files in their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 If local interactive users do not own the files in their directories, unauthorized users may be able to access them. Additionally, if files are not owned by the user, this could be an indication of system compromise. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $1 }' /etc/passwd); do home_dir=$(getent passwd $user | cut -d: -f6) # Only update the ownership when necessary. This will avoid changing the inode timestamp @@ -42844,11 +49627,27 @@ for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $ # check systems that also check inodes timestamps. find $home_dir -not -user $user -exec chown -f --no-dereference $user {} \; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_users_home_files_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_ownership - low_complexity @@ -42860,6 +49659,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_ownership - low_complexity @@ -42875,6 +49675,7 @@ done register: path_exists loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int >= 1000 - item.value[1]|int != 65534 - item.value[4] != "/" @@ -42892,7 +49693,9 @@ done owner: '{{ item.0.value[1] }}' recurse: true loop: '{{ local_users|zip(path_exists.results)|list }}' - when: item.1.stat is defined and item.1.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.1.stat is defined and item.1.stat.exists tags: - accounts_users_home_files_ownership - low_complexity @@ -42915,23 +49718,41 @@ directory with the following command: $ sudo chmod 0750 /home/USER/FILE_DIR Files that begin with a "." are excluded from this requirement. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 If a local interactive user files have excessive permissions, unintended users may be able to access or modify them. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $6 }' /etc/passwd); do # Only update the permissions when necessary. This will avoid changing the inode timestamp when # the permission is already defined as expected, therefore not impacting in possible integrity # check systems that also check inodes timestamps. find "$home_dir" -perm /7027 \! -type l -exec chmod u-s,g-w-s,o=- {} \; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_users_home_files_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_permissions - low_complexity @@ -42943,6 +49764,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_permissions - low_complexity @@ -42957,6 +49779,7 @@ done register: path_exists loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int >= 1000 - item.value[1]|int != 65534 - item.value[4] != "/" @@ -42976,7 +49799,9 @@ done follow: false recurse: true loop: '{{ local_users|zip(path_exists.results)|list }}' - when: item.1.stat is defined and item.1.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.1.stat is defined and item.1.stat.exists tags: - accounts_users_home_files_permissions - low_complexity @@ -43006,10 +49831,9 @@ are group-owners of one and only one home directory. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002514 - SV-271783r1092061_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002514 + SV-271783r1092061_rule If the Group Identifier (GID) of a local interactive users home directory is not the same as the primary GID of the user, this would allow unauthorized access to the users files, and users that share the same group may not be @@ -43090,11 +49914,10 @@ following command: $ sudo chmod 0740 /home/USER/.INIT_FILE - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002513 - SV-271782r1092058_rule + OL09-00-002513 + SV-271782r1092058_rule Local initialization files are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon. @@ -43193,10 +50016,9 @@ following command: $ sudo chmod 0750 /home/USER - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002515 - SV-271784r1092064_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002515 + SV-271784r1092064_rule Excessive permissions on local interactive user home directories may allow unauthorized access to user files by other users. @@ -43304,7 +50126,6 @@ updates as of version 0.1.62. DSS05.04 DSS05.07 DSS06.02 - CCI-000225 4.3.3.7.3 SR 2.1 SR 5.2 @@ -43331,15 +50152,15 @@ updates as of version 0.1.62. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) CM-6(a) @@ -43475,7 +50296,6 @@ other. BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -43492,7 +50312,7 @@ other. execute code provided by unprivileged users, and potentially malicious code. - name: Get root paths which are not symbolic links - stat: + ansible.builtin.stat: path: '{{ item }}' changed_when: false failed_when: false @@ -43509,7 +50329,7 @@ and potentially malicious code. - restrict_strategy - name: Disable writability to root directories - file: + ansible.builtin.file: path: '{{ item.item }}' mode: g-w,o-w with_items: '{{ root_paths.results }}' @@ -43552,7 +50372,6 @@ These empty elements have the same effect as a single . c BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -43591,6 +50410,7 @@ a member. + Sensible umask Enter default user umask @@ -43613,36 +50433,35 @@ as follows: BAI03.01 BAI03.02 BAI03.03 - CCI-000366 4.3.4.3.3 A.14.1.1 A.14.2.1 A.14.2.5 A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6(1) CM-6(a) PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 R36 A.6.SEC-OL5 - OL09-00-002301 - SV-271693r1091791_rule + OL09-00-002301 + SV-271693r1091791_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users. # Remediation is applicable only in certain platforms -if rpm --quiet -q bash; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q bash; }; then var_accounts_user_umask='' @@ -43688,7 +50507,9 @@ fi check_mode: true changed_when: false register: umask_replace - when: '"bash" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"bash" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002301 - NIST-800-53-AC-6(1) @@ -43706,6 +50527,7 @@ fi regexp: ^([^#]*\b)umask\s+\d+$ replace: \g<1>umask {{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"bash" in ansible_facts.packages' - umask_replace.found > 0 tags: @@ -43725,6 +50547,7 @@ fi path: /etc/bashrc line: umask {{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"bash" in ansible_facts.packages' - umask_replace.found == 0 tags: @@ -43758,32 +50581,33 @@ add or correct the umask setting in /etc/csh.c BAI03.01 BAI03.02 BAI03.03 - CCI-000366 4.3.4.3.3 A.14.1.1 A.14.2.1 A.14.2.5 A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6(1) CM-6(a) PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 - OL09-00-002302 - SV-271694r1091794_rule + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 + OL09-00-002302 + SV-271694r1091794_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_user_umask='' @@ -43792,8 +50616,25 @@ grep -q "^\s*umask" /etc/csh.cshrc && \ if ! [ $? -eq 0 ]; then echo "umask $var_accounts_user_umask" >> /etc/csh.cshrc fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_user_umask # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002302 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - accounts_umask_etc_csh_cshrc + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: var_accounts_user_umask: !!str tags: @@ -43807,6 +50648,7 @@ fi check_mode: true changed_when: false register: umask_replace + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) @@ -43823,7 +50665,9 @@ fi path: /etc/csh.cshrc regexp: ^(\s*)umask(\s+).* replace: \g<1>umask\g<2>{{ var_accounts_user_umask }} - when: umask_replace.found > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - umask_replace.found > 0 tags: - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) @@ -43840,7 +50684,9 @@ fi create: true path: /etc/csh.cshrc line: umask {{ var_accounts_user_umask }} - when: umask_replace.found == 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - umask_replace.found == 0 tags: - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) @@ -43879,7 +50725,6 @@ add or correct the UMASK setting in /etc/login BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -43893,30 +50738,30 @@ add or correct the UMASK setting in /etc/login A.14.2.4 A.14.2.5 A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6(1) CM-6(a) PR.IP-1 PR.IP-2 - SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00228 R36 A.6.SEC-OL5 - OL09-00-002304 - SV-271696r1091800_rule + OL09-00-002304 + SV-271696r1091800_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read and written to by unauthorized users. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_user_umask='' @@ -43972,7 +50817,9 @@ fi check_mode: true changed_when: false register: result_umask_is_set - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002304 - NIST-800-53-AC-6(1) @@ -43990,6 +50837,7 @@ fi regexp: ^(\s*)UMASK(\s+).* replace: \g<1>UMASK\g<2>{{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"shadow-utils" in ansible_facts.packages' - result_umask_is_set.found > 0 tags: @@ -44009,6 +50857,7 @@ fi path: /etc/login.defs line: UMASK {{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"shadow-utils" in ansible_facts.packages' - result_umask_is_set.found == 0 tags: @@ -44037,7 +50886,7 @@ add or correct the umask setting in /etc/profi umask -Note that /etc/profile also reads scrips within /etc/profile.d directory. +Note that /etc/profile also reads scripts within /etc/profile.d directory. These scripts are also valid files to set umask value. Therefore, they should also be considered during the check and properly remediated, if necessary. 18 @@ -44045,34 +50894,35 @@ considered during the check and properly remediated, if necessary.BAI03.01 BAI03.02 BAI03.03 - CCI-000366 4.3.4.3.3 A.14.1.1 A.14.2.1 A.14.2.5 A.6.1.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6(1) CM-6(a) PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 R36 A.6.SEC-OL5 - OL09-00-002303 - SV-271695r1091797_rule + OL09-00-002303 + SV-271695r1091797_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_user_umask='' @@ -44085,8 +50935,25 @@ done if ! grep -qrE '^[^#]*umask' /etc/profile*; then echo "umask $var_accounts_user_umask" >> /etc/profile fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_user_umask # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002303 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - accounts_umask_etc_profile + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: var_accounts_user_umask: !!str tags: @@ -44102,6 +50969,7 @@ fi - '*.sh' contains: ^[\s]*umask\s+\d+ register: result_profile_d_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44121,7 +50989,9 @@ fi replace: \1umask {{ var_accounts_user_umask }} loop: '{{ result_profile_d_files.files }}' register: result_umask_replaced_profile_d - when: result_profile_d_files.matched + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_profile_d_files.matched tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44140,7 +51010,9 @@ fi mode: 420 path: /etc/profile line: umask {{ var_accounts_user_umask }} - when: not result_profile_d_files.matched + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_profile_d_files.matched tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44159,6 +51031,7 @@ fi regexp: ^(\s*)umask\s+\d+ replace: \1umask {{ var_accounts_user_umask }} register: result_umask_replaced_profile + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44181,18 +51054,19 @@ fi Ensure the Default Umask is Set Correctly For Interactive Users Remove the UMASK environment variable from all interactive users initialization files. - CCI-000366 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00228 - OL09-00-003060 - SV-271848r1092256_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + OL09-00-003060 + SV-271848r1092256_rule The umask controls the default access mode assigned to newly created files. A umask of 077 limits new files to mode 700 or less permissive. Although umask can be represented as a four-digit number, the first digit representing special access modes is typically ignored or required to be 0. This requirement applies to the globally configured system defaults and the local interactive user defaults for each account on the system. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + while IFS= read -r dir; do while IFS= read -r -d '' file; do if [ "$(basename $file)" != ".bash_history" ]; then @@ -44200,18 +51074,96 @@ while IFS= read -r dir; do fi done < <(find $dir -maxdepth 1 -type f -name ".*" -print0) done < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6}' /etc/passwd) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure interactive local users are the owners of their respective initialization - files - ansible.builtin.shell: - cmd: |- - for dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6}' /etc/passwd); do - for file in $(find $dir -maxdepth 1 -type f -name ".*"); do - if [ "$(basename $file)" != ".bash_history" ]; then - sed -i 's/^\(\s*umask\s*\)/#\1/g' $file - fi - done - done + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Get interactive + users from passwd file + ansible.builtin.getent: + database: passwd + register: passwd_entries + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Filter interactive + users and get home directories + ansible.builtin.set_fact: + interactive_user_homes: '{{ interactive_user_homes | default([]) + [item.value[4]] + }}' + loop: '{{ passwd_entries.ansible_facts.getent_passwd | dict2items }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[2] | int >= 1000 | int + - item.value[2] | int != 65534 | int + - item.value[4] != "" + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Find dot + files in interactive user home directories + ansible.builtin.find: + paths: '{{ item }}' + patterns: .* + file_type: file + hidden: true + depth: 1 + register: user_dotfiles + with_items: '{{ interactive_user_homes | default([]) }}' + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item != "" + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Comment + out umask statements in user initialization files + ansible.builtin.replace: + path: '{{ item.1.path }}' + regexp: ^\s*umask\s+ + replace: '#\g<0>' + backup: false + with_subelements: + - '{{ user_dotfiles.results }}' + - files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.0 is not skipped + - item.1.path is defined + - '''.bash_history'' not in item.1.path' tags: - DISA-STIG-OL09-00-003060 - accounts_umask_interactive_users @@ -44318,12 +51270,13 @@ fi - reboot_required - restrict_strategy -- name: Verify GRUB_DISABLE_RECOVERY=true - lineinfile: +- name: Disable Recovery Booting - Verify GRUB_DISABLE_RECOVERY=true + ansible.builtin.lineinfile: path: /etc/default/grub regexp: ^GRUB_DISABLE_RECOVERY=.* line: GRUB_DISABLE_RECOVERY=true state: present + register: grub_config_changed when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44334,10 +51287,12 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL - when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages +- name: Disable Recovery Booting - Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) + - grub_config_changed is changed tags: - grub2_disable_recovery - low_complexity @@ -44371,15 +51326,12 @@ Run the following command to update command line for already installed kernels:< # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="force" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "iommu" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"iommu=[^\"]*\"(.*]\s*)/\1\"iommu=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"iommu=[^\"]*\"(.*]\s*)/\1\"iommu=force\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"iommu=$expected_value\"]" >> "$KARGS_DIR/10-iommu.toml" + echo "kargs = [\"iommu=force\"]" >> "$KARGS_DIR/10-iommu.toml" fi else @@ -44402,8 +51354,10 @@ fi - restrict_strategy - unknown_severity -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="iommu=force" +- name: Check if iommu argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44413,6 +51367,37 @@ fi - reboot_required - restrict_strategy - unknown_severity + +- name: Check if iommu argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_enable_iommu_force + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + - unknown_severity + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="iommu=force" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('iommu=force')) or ((etc_default_grub['content'] + | b64decode) is not search('iommu=force')) + tags: + - grub2_enable_iommu_force + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + - unknown_severity [customizations.kernel] append = "iommu=force" @@ -44443,15 +51428,12 @@ preventing data leaks. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "init_on_alloc" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"init_on_alloc=[^\"]*\"(.*]\s*)/\1\"init_on_alloc=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"init_on_alloc=[^\"]*\"(.*]\s*)/\1\"init_on_alloc=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"init_on_alloc=$expected_value\"]" >> "$KARGS_DIR/10-init_on_alloc.toml" + echo "kargs = [\"init_on_alloc=1\"]" >> "$KARGS_DIR/10-init_on_alloc.toml" fi else @@ -44474,8 +51456,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1" +- name: Check if init_on_alloc argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44485,6 +51469,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if init_on_alloc argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_init_on_alloc_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('init_on_alloc=1')) or ((etc_default_grub['content'] + | b64decode) is not search('init_on_alloc=1')) + tags: + - grub2_init_on_alloc_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "init_on_alloc=1" @@ -44529,15 +51544,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_l1tf_options='' -expected_value="$var_l1tf_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "l1tf" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"l1tf=[^\"]*\"(.*]\s*)/\1\"l1tf=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"l1tf=[^\"]*\"(.*]\s*)/\1\"l1tf=$var_l1tf_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"l1tf=$expected_value\"]" >> "$KARGS_DIR/10-l1tf.toml" + echo "kargs = [\"l1tf=$var_l1tf_options\"]" >> "$KARGS_DIR/10-l1tf.toml" fi else @@ -44565,8 +51579,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="l1tf={{ var_l1tf_options }}" +- name: Check if l1tf argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44576,6 +51592,38 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if l1tf argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_l1tf_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="l1tf={{ var_l1tf_options + }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('l1tf=' ~ var_l1tf_options)) or ((etc_default_grub['content'] + | b64decode) is not search('l1tf=' ~ var_l1tf_options)) + tags: + - grub2_l1tf_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "l1tf=" @@ -44611,15 +51659,12 @@ trying to exploit a vulnerability such as Rowhammer. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="0" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "mce" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mce=[^\"]*\"(.*]\s*)/\1\"mce=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mce=[^\"]*\"(.*]\s*)/\1\"mce=0\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"mce=$expected_value\"]" >> "$KARGS_DIR/10-mce.toml" + echo "kargs = [\"mce=0\"]" >> "$KARGS_DIR/10-mce.toml" fi else @@ -44642,8 +51687,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="mce=0" +- name: Check if mce argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44653,6 +51700,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if mce argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_mce_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="mce=0" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('mce=0')) or ((etc_default_grub['content'] | + b64decode) is not search('mce=0')) + tags: + - grub2_mce_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "mce=0" @@ -44706,15 +51784,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_mds_options='' -expected_value="$var_mds_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "mds" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mds=[^\"]*\"(.*]\s*)/\1\"mds=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mds=[^\"]*\"(.*]\s*)/\1\"mds=$var_mds_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"mds=$expected_value\"]" >> "$KARGS_DIR/10-mds.toml" + echo "kargs = [\"mds=$var_mds_options\"]" >> "$KARGS_DIR/10-mds.toml" fi else @@ -44742,8 +51819,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="mds={{ var_mds_options }}" +- name: Check if mds argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44753,6 +51832,38 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if mds argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_mds_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="mds={{ var_mds_options + }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('mds=' ~ var_mds_options)) or ((etc_default_grub['content'] + | b64decode) is not search('mds=' ~ var_mds_options)) + tags: + - grub2_mds_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "mds=" @@ -44772,7 +51883,7 @@ memory pages in the user space, it is enabled by default since Linux kernel 3.7. But it could be disabled through kernel boot parameters. Ensure that Supervisor Mode Access Prevention (SMAP) is not disabled by -the nosmap boot paramenter option. +the nosmap boot parameter option. Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub doesn't contain the argument nosmap. @@ -44785,7 +51896,7 @@ manipulation of data in the user space. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then sed -i -E "/kargs\s*=\s*\[\s*\"nosmap=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"nosmap=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" else @@ -44809,8 +51920,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="nosmap" +- name: Check if nosmap argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44820,6 +51933,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if nosmap argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_nosmap_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="nosmap" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is search('nosmap')) or ((etc_default_grub['content'] | b64decode) + is search('nosmap')) + tags: + - grub2_nosmap_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy @@ -44835,7 +51979,7 @@ it is enabled by default since Linux kernel 3.0. But it could be disabled throug kernel boot parameters. Ensure that Supervisor Mode Execution Prevention (SMEP) is not disabled by -the nosmep boot paramenter option. +the nosmep boot parameter option. Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub doesn't contain the argument nosmep. @@ -44848,7 +51992,7 @@ the kernel to unintentionally execute code in less privileged memory space.# Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then sed -i -E "/kargs\s*=\s*\[\s*\"nosmep=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"nosmep=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" else @@ -44872,8 +52016,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="nosmep" +- name: Check if nosmep argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44883,6 +52029,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if nosmep argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_nosmep_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="nosmep" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is search('nosmep')) or ((etc_default_grub['content'] | b64decode) + is search('nosmep')) + tags: + - grub2_nosmep_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy @@ -44917,15 +52094,12 @@ architecture. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "page_alloc.shuffle" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_alloc.shuffle=[^\"]*\"(.*]\s*)/\1\"page_alloc.shuffle=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_alloc.shuffle=[^\"]*\"(.*]\s*)/\1\"page_alloc.shuffle=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"page_alloc.shuffle=$expected_value\"]" >> "$KARGS_DIR/10-page_alloc_shuffle.toml" + echo "kargs = [\"page_alloc.shuffle=1\"]" >> "$KARGS_DIR/10-page_alloc_shuffle.toml" fi else @@ -44948,8 +52122,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1" +- name: Check if page_alloc.shuffle argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44959,6 +52135,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if page_alloc.shuffle argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_page_alloc_shuffle_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('page_alloc.shuffle=1')) or ((etc_default_grub['content'] + | b64decode) is not search('page_alloc.shuffle=1')) + tags: + - grub2_page_alloc_shuffle_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "page_alloc.shuffle=1" @@ -44982,14 +52189,12 @@ default Grub2 command line for Linux operating systems. Modify the line within GRUB_CMDLINE_LINUX="... pti=on ..." Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="pti=on" - CCI-002824 - CCI-000381 SI-16 - SRG-OS-000433-GPOS-00193 - SRG-OS-000095-GPOS-00049 + SRG-OS-000433-GPOS-00193 + SRG-OS-000095-GPOS-00049 R8 - OL09-00-002391 - SV-271735r1091917_rule + OL09-00-002391 + SV-271735r1091917_rule Kernel page-table isolation is a kernel feature that mitigates the Meltdown security vulnerability and hardens the kernel against attempts to bypass kernel address space layout @@ -44997,15 +52202,12 @@ randomization (KASLR). # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="on" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "pti" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"pti=[^\"]*\"(.*]\s*)/\1\"pti=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"pti=[^\"]*\"(.*]\s*)/\1\"pti=on\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"pti=$expected_value\"]" >> "$KARGS_DIR/10-pti.toml" + echo "kargs = [\"pti=on\"]" >> "$KARGS_DIR/10-pti.toml" fi else @@ -45030,8 +52232,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="pti=on" +- name: Check if pti argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45043,6 +52247,41 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if pti argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-002391 + - NIST-800-53-SI-16 + - grub2_pti_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="pti=on" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('pti=on')) or ((etc_default_grub['content'] + | b64decode) is not search('pti=on')) + tags: + - DISA-STIG-OL09-00-002391 + - NIST-800-53-SI-16 + - grub2_pti_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "pti=on" @@ -45090,15 +52329,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_rng_core_default_quality='' -expected_value="$var_rng_core_default_quality" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "rng_core.default_quality" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"rng_core.default_quality=[^\"]*\"(.*]\s*)/\1\"rng_core.default_quality=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"rng_core.default_quality=[^\"]*\"(.*]\s*)/\1\"rng_core.default_quality=$var_rng_core_default_quality\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"rng_core.default_quality=$expected_value\"]" >> "$KARGS_DIR/10-rng_core_default_quality.toml" + echo "kargs = [\"rng_core.default_quality=$var_rng_core_default_quality\"]" >> "$KARGS_DIR/10-rng_core_default_quality.toml" fi else @@ -45126,9 +52364,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="rng_core.default_quality={{ var_rng_core_default_quality - }}" +- name: Check if rng_core.default_quality argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45138,6 +52377,39 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if rng_core.default_quality argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_rng_core_default_quality_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="rng_core.default_quality={{ + var_rng_core_default_quality }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('rng_core.default_quality=' ~ var_rng_core_default_quality)) + or ((etc_default_grub['content'] | b64decode) is not search('rng_core.default_quality=' + ~ var_rng_core_default_quality)) + tags: + - grub2_rng_core_default_quality_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "rng_core.default_quality=" @@ -45176,15 +52448,12 @@ Overall, this reduces the kernel attack surface area by isolating slabs from eac # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="yes" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "slab_nomerge" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slab_nomerge=[^\"]*\"(.*]\s*)/\1\"slab_nomerge=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slab_nomerge=[^\"]*\"(.*]\s*)/\1\"slab_nomerge=yes\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"slab_nomerge=$expected_value\"]" >> "$KARGS_DIR/10-slab_nomerge.toml" + echo "kargs = [\"slab_nomerge=yes\"]" >> "$KARGS_DIR/10-slab_nomerge.toml" fi else @@ -45207,8 +52476,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="slab_nomerge=yes" +- name: Check if slab_nomerge argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45218,6 +52489,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if slab_nomerge argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_slab_nomerge_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="slab_nomerge=yes" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('slab_nomerge=yes')) or ((etc_default_grub['content'] + | b64decode) is not search('slab_nomerge=yes')) + tags: + - grub2_slab_nomerge_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "slab_nomerge=yes" @@ -45257,7 +52559,7 @@ Run the following command to update command line for already installed kernels:< Disabling Speculative Store Bypass may impact performance of the system. R8 - In vulnerable processsors, the speculatively forwarded store can be used in a cache side channel + In vulnerable processors, the speculatively forwarded store can be used in a cache side channel attack. An example of this is reading memory to which the attacker does not directly have access, for example inside the sandboxed code. # Remediation is applicable only in certain platforms @@ -45265,15 +52567,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_spec_store_bypass_disable_options='' -expected_value="$var_spec_store_bypass_disable_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "spec_store_bypass_disable" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spec_store_bypass_disable=[^\"]*\"(.*]\s*)/\1\"spec_store_bypass_disable=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spec_store_bypass_disable=[^\"]*\"(.*]\s*)/\1\"spec_store_bypass_disable=$var_spec_store_bypass_disable_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"spec_store_bypass_disable=$expected_value\"]" >> "$KARGS_DIR/10-spec_store_bypass_disable.toml" + echo "kargs = [\"spec_store_bypass_disable=$var_spec_store_bypass_disable_options\"]" >> "$KARGS_DIR/10-spec_store_bypass_disable.toml" fi else @@ -45301,9 +52602,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="spec_store_bypass_disable={{ var_spec_store_bypass_disable_options - }}" +- name: Check if spec_store_bypass_disable argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45313,6 +52615,39 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if spec_store_bypass_disable argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_spec_store_bypass_disable_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="spec_store_bypass_disable={{ + var_spec_store_bypass_disable_options }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('spec_store_bypass_disable=' ~ var_spec_store_bypass_disable_options)) + or ((etc_default_grub['content'] | b64decode) is not search('spec_store_bypass_disable=' + ~ var_spec_store_bypass_disable_options)) + tags: + - grub2_spec_store_bypass_disable_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "spec_store_bypass_disable=" @@ -45351,15 +52686,12 @@ access to. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="on" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "spectre_v2" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spectre_v2=[^\"]*\"(.*]\s*)/\1\"spectre_v2=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spectre_v2=[^\"]*\"(.*]\s*)/\1\"spectre_v2=on\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"spectre_v2=$expected_value\"]" >> "$KARGS_DIR/10-spectre_v2.toml" + echo "kargs = [\"spectre_v2=on\"]" >> "$KARGS_DIR/10-spectre_v2.toml" fi else @@ -45382,8 +52714,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="spectre_v2=on" +- name: Check if spectre_v2 argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45393,6 +52727,37 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if spectre_v2 argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_spectre_v2_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="spectre_v2=on" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('spectre_v2=on')) or ((etc_default_grub['content'] + | b64decode) is not search('spectre_v2=on')) + tags: + - grub2_spectre_v2_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "spectre_v2=on" @@ -45431,7 +52796,7 @@ access when the system is rebooted. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then sed -i -E "/kargs\s*=\s*\[\s*\"systemd.debug-shell=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"systemd.debug-shell=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" else @@ -45455,8 +52820,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.debug-shell" +- name: Check if systemd.debug-shell argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45466,6 +52833,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if systemd.debug-shell argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_systemd_debug-shell_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.debug-shell" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is search('systemd.debug-shell')) or ((etc_default_grub['content'] + | b64decode) is search('systemd.debug-shell')) + tags: + - grub2_systemd_debug-shell_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy @@ -45489,29 +52887,24 @@ Run the following command to update command line for already installed kernels:< The vsyscall emulation is only available on x86_64 architecture (CONFIG_X86_VSYSCALL_EMULATION) making this rule not applicable to other CPU architectures. - CCI-000366 - CCI-001084 CM-7(a) FPT_ASLR_EXT.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - OL09-00-002393 - SV-271737r1094967_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + OL09-00-002393 + SV-271737r1094967_rule Virtual Syscalls provide an opportunity of attack for a user who has control of the return instruction pointer. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ( grep -sqE "^.*\.x86_64$" /proc/sys/kernel/osrelease || grep -sqE "^x86_64$" /proc/sys/kernel/arch; ); }; then -expected_value="none" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "vsyscall" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"vsyscall=[^\"]*\"(.*]\s*)/\1\"vsyscall=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"vsyscall=[^\"]*\"(.*]\s*)/\1\"vsyscall=none\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"vsyscall=$expected_value\"]" >> "$KARGS_DIR/10-vsyscall.toml" + echo "kargs = [\"vsyscall=none\"]" >> "$KARGS_DIR/10-vsyscall.toml" fi else @@ -45536,8 +52929,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none" +- name: Check if vsyscall argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) @@ -45551,6 +52946,44 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if vsyscall argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - ansible_architecture == "x86_64" + tags: + - DISA-STIG-OL09-00-002393 + - NIST-800-53-CM-7(a) + - grub2_vsyscall_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - ansible_architecture == "x86_64" + - (grubby_info.stdout is not search('vsyscall=none')) or ((etc_default_grub['content'] + | b64decode) is not search('vsyscall=none')) + tags: + - DISA-STIG-OL09-00-002393 + - NIST-800-53-CM-7(a) + - grub2_vsyscall_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "vsyscall=none" @@ -45565,7 +52998,6 @@ append = "vsyscall=none" Non-UEFI GRUB2 bootloader configuration Non-UEFI GRUB2 bootloader configuration - Verify /boot/grub2/grub.cfg Group Ownership The file /boot/grub2/grub.cfg should @@ -45573,7 +53005,8 @@ be group-owned by the root group to prevent destruction or modification of the file. To properly set the group owner of /boot/grub2/grub.cfg, run the command: -$ sudo chgrp root /boot/grub2/grub.cfg + + $ sudo chgrp root /boot/grub2/grub.cfg 12 13 @@ -45589,7 +53022,6 @@ To properly set the group owner of /boot/grub2/grub.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -45632,20 +53064,32 @@ To properly set the group owner of /boot/grub2/grub.cfg, PR.AC-4 PR.DS-5 Req-7.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R29 A.6.SEC-OL2 2.2.6 2.2 - OL09-00-002530 - SV-271792r1094968_rule + OL09-00-002530 + SV-271792r1094968_rule The root group is a highly-privileged group. Furthermore, the group-owner of this file should not have any access privileges anyway. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chgrp 0 /boot/grub2/grub.cfg +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/boot/grub2/grub.cfg" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /boot/grub2/grub.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -45670,16 +53114,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists +- name: Set the file_groupowner_grub2_cfg_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_grub2_cfg_newgroup: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -45697,16 +53138,40 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /boot/grub2/grub.cfg - file: +- name: Test for existence /boot/grub2/grub.cfg + ansible.builtin.stat: path: /boot/grub2/grub.cfg - group: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002530 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/grub2/grub.cfg + ansible.builtin.file: + path: /boot/grub2/grub.cfg + follow: false + group: '{{ file_groupowner_grub2_cfg_newgroup }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -45738,7 +53203,8 @@ fi group to prevent reading or modification of the file. To properly set the group owner of /boot/grub2/user.cfg, run the command: -$ sudo chgrp root /boot/grub2/user.cfg + + $ sudo chgrp root /boot/grub2/user.cfg 12 13 @@ -45754,7 +53220,6 @@ To properly set the group owner of /boot/grub2/user.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -45797,7 +53262,7 @@ To properly set the group owner of /boot/grub2/user.cfg, PR.AC-4 PR.DS-5 Req-7.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R29 A.6.SEC-OL2 2.2.6 @@ -45805,11 +53270,23 @@ To properly set the group owner of /boot/grub2/user.cfg, The root group is a highly-privileged group. Furthermore, the group-owner of this file should not have any access privileges anyway. Non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chgrp 0 /boot/grub2/user.cfg +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/boot/grub2/user.cfg" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /boot/grub2/user.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -45833,16 +53310,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists +- name: Set the file_groupowner_user_cfg_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_user_cfg_newgroup: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -45859,16 +53333,39 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /boot/grub2/user.cfg - file: +- name: Test for existence /boot/grub2/user.cfg + ansible.builtin.stat: path: /boot/grub2/user.cfg - group: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/grub2/user.cfg + ansible.builtin.file: + path: /boot/grub2/user.cfg + follow: false + group: '{{ file_groupowner_user_cfg_newgroup }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -45900,7 +53397,8 @@ be owned by the root user to prevent destruction or modification of the file. To properly set the owner of /boot/grub2/grub.cfg, run the command: -$ sudo chown root /boot/grub2/grub.cfg + + $ sudo chown root /boot/grub2/grub.cfg 12 13 @@ -45916,7 +53414,6 @@ To properly set the owner of /boot/grub2/grub.cfg, run th DSS05.07 DSS06.02 3.4.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -45959,19 +53456,31 @@ To properly set the owner of /boot/grub2/grub.cfg, run th PR.AC-4 PR.DS-5 Req-7.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R29 A.6.SEC-OL2 2.2.6 2.2 - OL09-00-002531 - SV-271793r1092605_rule + OL09-00-002531 + SV-271793r1092605_rule Only root should be able to modify important boot parameters. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chown 0 /boot/grub2/grub.cfg +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/boot/grub2/grub.cfg" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /boot/grub2/grub.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -45996,16 +53505,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists +- name: Set the file_owner_grub2_cfg_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_grub2_cfg_newown: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -46023,16 +53529,40 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /boot/grub2/grub.cfg - file: +- name: Test for existence /boot/grub2/grub.cfg + ansible.builtin.stat: path: /boot/grub2/grub.cfg - owner: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002531 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /boot/grub2/grub.cfg + ansible.builtin.file: + path: /boot/grub2/grub.cfg + follow: false + owner: '{{ file_owner_grub2_cfg_newown }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46064,7 +53594,8 @@ fi user to prevent reading or modification of the file. To properly set the owner of /boot/grub2/user.cfg, run the command: -$ sudo chown root /boot/grub2/user.cfg + + $ sudo chown root /boot/grub2/user.cfg 12 13 @@ -46080,7 +53611,6 @@ To properly set the owner of /boot/grub2/user.cfg, run th DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46130,11 +53660,23 @@ To properly set the owner of /boot/grub2/user.cfg, run th Only root should be able to modify important boot parameters. Also, non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chown 0 /boot/grub2/user.cfg +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/boot/grub2/user.cfg" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /boot/grub2/user.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -46158,16 +53700,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists +- name: Set the file_owner_user_cfg_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_user_cfg_newown: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -46184,16 +53723,39 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /boot/grub2/user.cfg - file: +- name: Test for existence /boot/grub2/user.cfg + ansible.builtin.stat: path: /boot/grub2/user.cfg - owner: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /boot/grub2/user.cfg + ansible.builtin.file: + path: /boot/grub2/user.cfg + follow: false + owner: '{{ file_owner_user_cfg_newown }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46238,7 +53800,6 @@ To properly set the permissions of /boot/grub2/grub.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46286,9 +53847,9 @@ To properly set the permissions of /boot/grub2/grub.cfg, 2.2 Proper permissions ensure that only the root user can modify important boot parameters. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then chmod u-xs,g-xwrs,o-xwrt /boot/grub2/grub.cfg @@ -46313,15 +53874,13 @@ fi - no_reboot_needed - name: Test for existence /boot/grub2/grub.cfg - stat: + ansible.builtin.stat: path: /boot/grub2/grub.cfg register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - NIST-800-171-3.4.5 @@ -46337,15 +53896,13 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/grub.cfg - file: + ansible.builtin.file: path: /boot/grub2/grub.cfg mode: u-xs,g-xwrs,o-xwrt when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46388,7 +53945,6 @@ To properly set the permissions of /boot/grub2/user.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46436,9 +53992,9 @@ To properly set the permissions of /boot/grub2/user.cfg, 2.2 Proper permissions ensure that only the root user can read or modify important boot parameters. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then chmod u-xs,g-xwrs,o-xwrt /boot/grub2/user.cfg @@ -46463,15 +54019,13 @@ fi - no_reboot_needed - name: Test for existence /boot/grub2/user.cfg - stat: + ansible.builtin.stat: path: /boot/grub2/user.cfg register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - NIST-800-171-3.4.5 @@ -46487,15 +54041,13 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/user.cfg - file: + ansible.builtin.file: path: /boot/grub2/user.cfg mode: u-xs,g-xwrs,o-xwrt when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages - and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46534,7 +54086,10 @@ admin, or administrator for the grub2 superuser account. Change the superuser to a different username (The default is 'root'). $ sed -i 's/\(set superusers=\).*/\1"<unique user ID>"/g' /etc/grub.d/01_users - +The line mentioned above must be followed by the line +export superusers +so that the superusers is honored. + Once the superuser account has been added, update the @@ -46564,7 +54119,6 @@ Also, do NOT manually add the superuser account and password to the DSS06.06 DSS06.10 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46639,9 +54193,9 @@ Also, do NOT manually add the superuser account and password to the PR.AC-6 PR.AC-7 PR.PT-3 - SRG-OS-000080-GPOS-00048 - OL09-00-000050 - SV-271451r1091065_rule + SRG-OS-000080-GPOS-00048 + OL09-00-000050 + SV-271451r1117265_rule Having a non-default grub superuser username makes password-guessing attacks less effective. @@ -46688,7 +54242,6 @@ Also, do NOT manually add the superuser account and password to the DSS06.06 DSS06.10 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46763,15 +54316,17 @@ Also, do NOT manually add the superuser account and password to the PR.AC-6 PR.AC-7 PR.PT-3 - SRG-OS-000080-GPOS-00048 + FIA_UAU.1 + SRG-OS-000080-GPOS-00048 R5 A.8.SEC-OL7 - OL09-00-001115 - SV-271635r1091617_rule + OL09-00-001115 + SV-271635r1117265_rule Password protection on the boot loader configuration ensures users with physical access cannot trivially alter important bootloader settings. These include which kernel to use, and whether to enter single-user mode. + @@ -46787,147 +54342,14 @@ and whether to enter single-user mode. managed by chmod command. In this case, in order to change file permissions for files within /boot/efi it is necessary to update the mount options in /etc/fstab file and reboot the system. - - - Verify the UEFI Boot Loader grub.cfg Group Ownership - The file /boot/grub2/grub.cfg should -be group-owned by the root group to prevent -destruction or modification of the file. - -To properly set the group owner of /boot/grub2/grub.cfg, run the command: -$ sudo chgrp root /boot/grub2/grub.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - R29 - The root group is a highly-privileged group. Furthermore, the group-owner of this -file should not have any access privileges anyway. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chgrp 0 /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - group: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - Verify /boot/grub2/user.cfg Group Ownership The file /boot/grub2/user.cfg should be group-owned by the root group to prevent reading or modification of the file. To properly set the group owner of /boot/grub2/user.cfg, run the command: -$ sudo chgrp root /boot/grub2/user.cfg + + $ sudo chgrp root /boot/grub2/user.cfg 12 13 @@ -46943,7 +54365,6 @@ To properly set the group owner of /boot/grub2/user.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 4.3.3.7.3 SR 2.1 SR 5.2 @@ -46980,9 +54401,21 @@ To properly set the group owner of /boot/grub2/user.cfg, file should not have any access privileges anyway. Non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them. # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -chgrp 0 /boot/grub2/user.cfg +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/boot/grub2/user.cfg" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /boot/grub2/user.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -47004,13 +54437,10 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages +- name: Set the file_groupowner_efi_user_cfg_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_efi_user_cfg_newgroup: '0' + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2.2 @@ -47025,12 +54455,31 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /boot/grub2/user.cfg - file: +- name: Test for existence /boot/grub2/user.cfg + ansible.builtin.stat: path: /boot/grub2/user.cfg - group: '0' + register: file_exists + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/grub2/user.cfg + ansible.builtin.file: + path: /boot/grub2/user.cfg + follow: false + group: '{{ file_groupowner_efi_user_cfg_newgroup }}' when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - file_exists.stat is defined and file_exists.stat.exists @@ -47054,632 +54503,6 @@ fi - - Verify the UEFI Boot Loader grub.cfg User Ownership - The file /boot/grub2/grub.cfg should -be owned by the root user to prevent destruction -or modification of the file. - -To properly set the owner of /boot/grub2/grub.cfg, run the command: -$ sudo chown root /boot/grub2/grub.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - R29 - Only root should be able to modify important boot parameters. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chown 0 /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - owner: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/user.cfg User Ownership - The file /boot/grub2/user.cfg should be owned by the root -user to prevent reading or modification of the file. - -To properly set the owner of /boot/grub2/user.cfg, run the command: -$ sudo chown root /boot/grub2/user.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - R29 - Only root should be able to modify important boot parameters. Also, non-root users who read -the boot parameters may be able to identify weaknesses in security upon boot and be able to -exploit them. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chown 0 /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - owner: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify the UEFI Boot Loader grub.cfg Permissions - File permissions for /boot/grub2/grub.cfg should be set to 700. - -To properly set the permissions of /boot/grub2/grub.cfg, run the command: -$ sudo chmod 700 /boot/grub2/grub.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - R29 - Proper permissions ensure that only the root user can modify important boot -parameters. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chmod u-s,g-xwrs,o-xwrt /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-s,g-xwrs,o-xwrt on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - mode: u-s,g-xwrs,o-xwrt - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/user.cfg Permissions - File permissions for /boot/grub2/user.cfg should be set to 600. - -To properly set the permissions of /boot/grub2/user.cfg, run the command: -$ sudo chmod 600 /boot/grub2/user.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 4.3.3.7.3 - SR 2.1 - SR 5.2 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.6.1.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - R29 - Proper permissions ensure that only the root user can read or modify important boot -parameters. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chmod u-s,g-xwrs,o-xwrt /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-s,g-xwrs,o-xwrt on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - mode: u-s,g-xwrs,o-xwrt - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Set the UEFI Boot Loader Password - The grub2 boot loader should have a superuser account and password -protection enabled to protect boot-time settings. - - -Since plaintext passwords are a security risk, generate a hash for the password -by running the following command: - -# grub2-setpassword - -When prompted, enter the password that was selected. - - - - To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation -must be automated as a component of machine provisioning, or followed manually as outlined above. - -Also, do NOT manually add the superuser account and password to the -grub.cfg file as the grub2-mkconfig command overwrites this file. - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.4.5 - CCI-000213 - 164.308(a)(1)(ii)(B) - 164.308(a)(7)(i) - 164.308(a)(7)(ii)(A) - 164.310(a)(1) - 164.310(a)(2)(i) - 164.310(a)(2)(ii) - 164.310(a)(2)(iii) - 164.310(b) - 164.310(c) - 164.310(d)(1) - 164.310(d)(2)(iii) - 4.3.3.2.2 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - A.6.1.2 - A.7.1.1 - A.9.1.2 - A.9.2.1 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(a) - PR.AC-4 - PR.AC-6 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - R5 - Password protection on the boot loader configuration ensures -users with physical access cannot trivially alter -important bootloader settings. These include which kernel to use, -and whether to enter single-user mode. - - - - - - - @@ -47774,7 +54597,7 @@ The configuration that was used to build kernel is available at /boot There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. R27 The Privileged Access Never (PAN) is the ARM equivalent of the x86 Supervisor Mode Access -Prevention (SMAP), and it prevents privileged acccess to user data unless explicitly enabled. +Prevention (SMAP), and it prevents privileged access to user data unless explicitly enabled. @@ -47881,7 +54704,7 @@ The configuration that was used to build kernel is available at /boot Certain buggy versions of glibc (2.3.3) will crash if they are presented with a 32-bit vDSO that is not mapped at the address indicated in its segment table. Setting CONFIG_COMPAT_VDSO to y turns off the 32-bit VDSO and works -aroud the glibc bug. +around the glibc bug. The configuration that was used to build kernel is available at /boot/config-*. To check the configuration value for CONFIG_COMPAT_VDSO, run the following command: @@ -47960,7 +54783,7 @@ The configuration that was used to build kernel is available at /boot There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. R16 This add sanity checks to manipulation of linked lists structures in the kernel and may -prevent exploits such as CVE-2017-1661, where a race condition and simultaneos operations +prevent exploits such as CVE-2017-1661, where a race condition and simultaneous operations caused a list to corrupt. @@ -49002,7 +55825,7 @@ allocated when they are released. - Stack Protector buffer overlow detection + Stack Protector buffer overflow detection This feature puts, at the beginning of functions, a canary value on the stack just before the return address, and validates the value just before actually returning. This configuration is available from kernel 4.18. @@ -49348,13 +56171,11 @@ The rsyslog-gnutls package can be installed with the foll $ sudo yum install rsyslog-gnutls - CCI-000366 - CCI-000803 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 R71 - OL09-00-000355 - SV-271510r1091242_rule + OL09-00-000355 + SV-271510r1091242_rule The rsyslog-gnutls package provides Transport Layer Security (TLS) support for the rsyslog daemon, which enables secure remote logging. # Remediation is applicable only in certain platforms @@ -49381,7 +56202,7 @@ fi - package_rsyslog-gnutls_installed - name: Ensure rsyslog-gnutls is installed - package: + ansible.builtin.package: name: rsyslog-gnutls state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -49433,9 +56254,6 @@ version = "*" DSS05.04 DSS05.07 MEA02.01 - CCI-000366 - CCI-000154 - CCI-001851 164.312(a)(2)(ii) 4.3.3.3.9 4.3.3.5.8 @@ -49455,11 +56273,12 @@ version = "*" A.12.7.1 CM-6(a) PR.PT-1 - SRG-OS-000479-GPOS-00224 - SRG-OS-000051-GPOS-00024 - SRG-OS-000480-GPOS-00227 - OL09-00-000350 - SV-271508r1091236_rule + SRG-OS-000479-GPOS-00224 + SRG-OS-000051-GPOS-00024 + SRG-OS-000480-GPOS-00227 + 1409 + OL09-00-000350 + SV-271508r1091236_rule The rsyslog package provides the rsyslog daemon, which provides system logging services. # Remediation is applicable only in certain platforms @@ -49487,7 +56306,7 @@ fi - package_rsyslog_installed - name: Ensure rsyslog is installed - package: + ansible.builtin.package: name: rsyslog state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -49564,7 +56383,6 @@ The rsyslog service can be enabled with the following com MEA01.04 MEA01.05 MEA02.01 - CCI-000366 164.312(a)(2)(ii) 4.3.2.6.7 4.3.3.3.9 @@ -49600,9 +56418,10 @@ The rsyslog service can be enabled with the following com ID.SC-4 PR.DS-4 PR.PT-1 - SRG-OS-000480-GPOS-00227 - OL09-00-000351 - SV-271509r1091239_rule + SRG-OS-000480-GPOS-00227 + 1409 + OL09-00-000351 + SV-271509r1091239_rule The rsyslog service must be running in order to provide logging services, which are essential to system administration. # Remediation is applicable only in certain platforms @@ -49637,7 +56456,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable rsyslog Service - Enable Service rsyslog @@ -49648,7 +56467,6 @@ fi masked: false when: - '"rsyslog" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000351 - NIST-800-53-AU-4(1) @@ -49659,6 +56477,8 @@ fi - medium_severity - no_reboot_needed - service_rsyslog_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_rsyslog @@ -49673,6 +56493,10 @@ class enable_rsyslog { [customizations.services] enabled = ["rsyslog"] + + + + @@ -49735,7 +56559,6 @@ If the modern syntax (RainerScript) is used: MEA01.04 MEA01.05 MEA02.01 - CCI-000366 4.3.2.6.7 4.3.3.3.9 4.3.3.5.8 @@ -49749,8 +56572,6 @@ If the modern syntax (RainerScript) is used: SR 2.8 SR 2.9 SR 6.1 - 0988 - 1405 A.12.4.1 A.12.4.2 A.12.4.3 @@ -49761,22 +56582,34 @@ If the modern syntax (RainerScript) is used: CM-6(a) ID.SC-4 PR.PT-1 - SRG-OS-000480-GPOS-00227 - OL09-00-005010 - SV-271853r1092271_rule + SRG-OS-000480-GPOS-00227 + 0988 + 1405 + OL09-00-005010 + SV-271853r1092271_rule Cron logging can be used to trace the successful or unsuccessful execution of cron jobs. It can also be used to spot intrusions into the use of the cron facility by unauthorized and malicious users. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -if ! grep -Pzo '(?m)^\s*(cron|\*)\.\*\s*(/var/log/(cron|messages)|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/(cron|messages)"\s*\))\s*$' /etc/rsyslog.conf /etc/rsyslog.d/*.conf; then +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove all multilined cron.* entries +sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' {} + +# remove all legacy format and one line cron.* entries +sed -i '/^\s*\*\.\*\s+/var/log/cron\s*$/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^\s*\*\.\*\s+/var/log/cron\s*$/d' {} + +sed -i '/^[[:space:]]*cron\.\*/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*cron\.\*/d' {} + - mkdir -p /etc/rsyslog.d - echo "cron.* /var/log/cron" >> /etc/rsyslog.d/cron.conf -fi +echo "cron.* /var/log/cron" >> $RSYSLOG_D_CONF -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then systemctl restart rsyslog.service fi @@ -49797,11 +56630,12 @@ fi - no_reboot_needed - rsyslog_cron_logging -- name: Ensure cron Is Logging To Rsyslog - Search if cron configuration exists - ansible.builtin.command: grep -Pzo '(?m)^\s*(cron|\*)\.\*\s*(/var/log/(cron|messages)|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/(cron|messages)"\s*\))\s*$' - /etc/rsyslog.conf /etc/rsyslog.d/*.conf - register: cron_log_config_exists - failed_when: false +- name: Ensure cron Is Logging To Rsyslog - Ensure /etc/rsyslog.conf exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -49815,7 +56649,7 @@ fi - no_reboot_needed - rsyslog_cron_logging -- name: Ensure cron Is Logging To Rsyslog - Ensure the /etc/rsyslog.d directory exists +- name: Ensure cron Is Logging To Rsyslog - Ensure /etc/rsyslog.d directory exists ansible.builtin.file: path: /etc/rsyslog.d state: directory @@ -49832,15 +56666,163 @@ fi - no_reboot_needed - rsyslog_cron_logging -- name: Ensure cron Is Logging To Rsyslog - Add cron log configuration line - ansible.builtin.lineinfile: - path: /etc/rsyslog.d/cron.conf - line: cron.* /var/log/cron - create: true +- name: Ensure cron Is Logging To Rsyslog - Remove multilined cron.* action() entries + from rsyslog.conf + ansible.builtin.shell: sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' /etc/rsyslog.conf + changed_when: true when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - cron_log_config_exists.stdout_lines | length == 0 + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Remove multilined cron.* action() entries + from rsyslog.d/*.conf + ansible.builtin.shell: find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' + {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Remove *.* entries pointing to /var/log/cron from rsyslog.conf + ansible.builtin.lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: (?i)^\s*\*\.\*\s+/var/log/cron\s*$ + state: absent + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Remove *.* entries pointing to /var/log/cron + from rsyslog.d/*.conf + ansible.builtin.shell: find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '\|^\s*\*\.\*\s\+/var/log/cron\s*$|d' + {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Check if the parameter cron.* is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "cron.*"| regex_escape }} + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Check if the parameter cron.* is configured + correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "cron.*"| regex_escape }}/var/log/cron$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog + block: + + - name: Deduplicate values from /etc/rsyslog.conf + ansible.builtin.lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: (?i)^\s*{{ "cron.*"| regex_escape }} + state: absent + + - name: Check if /etc/rsyslog.d exists + ansible.builtin.stat: + path: /etc/rsyslog.d + register: _etc_rsyslog_d_exists + + - name: Check if the parameter cron.* is present in /etc/rsyslog.d + ansible.builtin.find: + paths: /etc/rsyslog.d + recurse: 'yes' + follow: 'no' + contains: ^\s*{{ "cron.*"| regex_escape }} + register: _etc_rsyslog_d_has_parameter + when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/rsyslog.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)^\s*{{ "cron.*"| regex_escape }} + state: absent + with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' + when: _etc_rsyslog_d_has_parameter.matched + + - name: Insert correct line to /etc/rsyslog.d/cron.conf + ansible.builtin.lineinfile: + path: /etc/rsyslog.d/cron.conf + create: true + regexp: (?i)^\s*{{ "cron.*"| regex_escape }} + line: cron.* /var/log/cron + state: present + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005010 - NIST-800-53-CM-6(a) @@ -49890,34 +56872,43 @@ Set the following configuration option in /etc/rsyslog.conf or in a file in /etc Alternatively, use the RainerScript syntax: action(type="omfwd" Target="some.example.com" StreamDriverAuthMode="x509/name") - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-005015 - SV-271854r1092274_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005015 + SV-271854r1092274_rule The audit records generated by Rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Audit records should be protected from unauthorized access. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -sed -i '/^.*\$ActionSendStreamDriverAuthMode.*/d' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2> /dev/null +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove legacy entries +sed -i '/^[[:space:]]*\$ActionSendStreamDriverAuthMode/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*\$ActionSendStreamDriverAuthMode/d' {} + +# remove all multilined and onelined RainerScript entries +sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' {} + -if [ -e "/etc/rsyslog.d/stream_driver_auth.conf" ] ; then +if [ -e "$RSYSLOG_D_CONF" ] ; then - LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverAuthMode /Id" "/etc/rsyslog.d/stream_driver_auth.conf" + LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverAuthMode /Id" "$RSYSLOG_D_CONF" else - touch "/etc/rsyslog.d/stream_driver_auth.conf" + touch "$RSYSLOG_D_CONF" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/stream_driver_auth.conf" +sed -i -e '$a\' "$RSYSLOG_D_CONF" -cp "/etc/rsyslog.d/stream_driver_auth.conf" "/etc/rsyslog.d/stream_driver_auth.conf.bak" +cp "$RSYSLOG_D_CONF" "$RSYSLOG_D_CONF.bak" # Insert at the end of the file -printf '%s\n' "\$ActionSendStreamDriverAuthMode x509/name" >> "/etc/rsyslog.d/stream_driver_auth.conf" +printf '%s\n' "\$ActionSendStreamDriverAuthMode x509/name" >> "$RSYSLOG_D_CONF" # Clean up after ourselves. -rm "/etc/rsyslog.d/stream_driver_auth.conf.bak" +rm "$RSYSLOG_D_CONF.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -49936,23 +56927,139 @@ fi - no_reboot_needed - rsyslog_encrypt_offload_actionsendstreamdriverauthmode +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Ensure /etc/rsyslog.conf + exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Ensure /etc/rsyslog.d + directory exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Remove RainerScript + action() entries with StreamDriverAuthMode from rsyslog.conf + ansible.builtin.shell: | + sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' /etc/rsyslog.conf + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Remove RainerScript + action() entries with StreamDriverAuthMode from rsyslog.d/*.conf + ansible.builtin.shell: | + find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverAuthMode is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverAuthMode is configured correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\sx509/name$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + - name: Ensure Rsyslog Authenticates Off-Loaded Audit Records block: - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: false regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s state: absent - name: Check if /etc/rsyslog.d exists - stat: + ansible.builtin.stat: path: /etc/rsyslog.d register: _etc_rsyslog_d_exists - name: Check if the parameter $ActionSendStreamDriverAuthMode is present in /etc/rsyslog.d - find: + ansible.builtin.find: paths: /etc/rsyslog.d recurse: 'yes' follow: 'no' @@ -49961,7 +57068,7 @@ fi when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' create: false regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s @@ -49970,7 +57077,7 @@ fi when: _etc_rsyslog_d_has_parameter.matched - name: Insert correct line to /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: true regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s @@ -49979,6 +57086,7 @@ fi when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005015 - NIST-800-53-AU-4(1) @@ -50004,7 +57112,7 @@ and remote logging. Couple this utility with gnutls (whi library implementing the SSL, TLS and DTLS protocols), and you have a method to securely encrypt and off-load auditing. -When using rsyslogd to off-load logs off a encrpytion system must be used. +When using rsyslogd to off-load logs off a encryption system must be used. Set the following configuration option in /etc/rsyslog.conf or in a file in /etc/rsyslog.d (using legacy syntax): $ActionSendStreamDriverMode 1 @@ -50012,32 +57120,43 @@ Set the following configuration option in /etc/rsyslog.conf or in a file in /etc Alternatively, use the RainerScript syntax: action(type="omfwd" ... StreamDriverMode="1") - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-005020 - SV-271855r1092277_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005020 + SV-271855r1092277_rule The audit records generated by Rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Audit records should be protected from unauthorized access. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove ActionSendStreamDriverMode entries +sed -i '/^[[:space:]]*\$ActionSendStreamDriverMode/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*\$ActionSendStreamDriverMode/d' {} + +# remove all multilined and onelined RainerScript entries +sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' {} + + +if [ -e "$RSYSLOG_D_CONF" ] ; then - LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverMode /Id" "/etc/rsyslog.d/encrypt.conf" + LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverMode /Id" "$RSYSLOG_D_CONF" else - touch "/etc/rsyslog.d/encrypt.conf" + touch "$RSYSLOG_D_CONF" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" +sed -i -e '$a\' "$RSYSLOG_D_CONF" -cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" +cp "$RSYSLOG_D_CONF" "$RSYSLOG_D_CONF.bak" # Insert at the end of the file -printf '%s\n' "\$ActionSendStreamDriverMode 1" >> "/etc/rsyslog.d/encrypt.conf" +printf '%s\n' "\$ActionSendStreamDriverMode 1" >> "$RSYSLOG_D_CONF" # Clean up after ourselves. -rm "/etc/rsyslog.d/encrypt.conf.bak" +rm "$RSYSLOG_D_CONF.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -50056,23 +57175,139 @@ fi - no_reboot_needed - rsyslog_encrypt_offload_actionsendstreamdrivermode +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.conf + exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.d directory + exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript action() + entries with StreamDriverMode from rsyslog.conf + ansible.builtin.shell: | + sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' /etc/rsyslog.conf + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript action() + entries with StreamDriverMode from rsyslog.d/*.conf + ansible.builtin.shell: | + find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverMode is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverMode is configured correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} 1$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + - name: Ensure Rsyslog Encrypts Off-Loaded Audit Records block: - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: false regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' state: absent - name: Check if /etc/rsyslog.d exists - stat: + ansible.builtin.stat: path: /etc/rsyslog.d register: _etc_rsyslog_d_exists - name: Check if the parameter $ActionSendStreamDriverMode is present in /etc/rsyslog.d - find: + ansible.builtin.find: paths: /etc/rsyslog.d recurse: 'yes' follow: 'no' @@ -50081,7 +57316,7 @@ fi when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' create: false regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' @@ -50090,7 +57325,7 @@ fi when: _etc_rsyslog_d_has_parameter.matched - name: Insert correct line to /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: true regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' @@ -50099,6 +57334,7 @@ fi when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005020 - NIST-800-53-AU-4(1) @@ -50132,32 +57368,43 @@ Set the following configuration option in /etc/rsyslog.conf or in a file in /etc Alternatively, use the RainerScript syntax: global(DefaultNetstreamDriver="gtls") - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-005025 - SV-271856r1092280_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005025 + SV-271856r1092280_rule The audit records generated by Rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Audit records should be protected from unauthorized access. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove DefaultNetstreamDriver entries +sed -i '/^[[:space:]]*\$DefaultNetstreamDriver/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*\$DefaultNetstreamDriver/d' {} + +# remove all multilined and onelined RainerScript entries +sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' {} + + +if [ -e "$RSYSLOG_D_CONF" ] ; then - LC_ALL=C sed -i "/^\s*\$DefaultNetstreamDriver /Id" "/etc/rsyslog.d/encrypt.conf" + LC_ALL=C sed -i "/^\s*\$DefaultNetstreamDriver /Id" "$RSYSLOG_D_CONF" else - touch "/etc/rsyslog.d/encrypt.conf" + touch "$RSYSLOG_D_CONF" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" +sed -i -e '$a\' "$RSYSLOG_D_CONF" -cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" +cp "$RSYSLOG_D_CONF" "$RSYSLOG_D_CONF.bak" # Insert at the end of the file -printf '%s\n' "\$DefaultNetstreamDriver gtls" >> "/etc/rsyslog.d/encrypt.conf" +printf '%s\n' "\$DefaultNetstreamDriver gtls" >> "$RSYSLOG_D_CONF" # Clean up after ourselves. -rm "/etc/rsyslog.d/encrypt.conf.bak" +rm "$RSYSLOG_D_CONF.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -50176,23 +57423,139 @@ fi - no_reboot_needed - rsyslog_encrypt_offload_defaultnetstreamdriver +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.conf + exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.d directory + exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript global() + entries with DefaultNetstreamDriver from rsyslog.conf + ansible.builtin.shell: | + sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' /etc/rsyslog.conf + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript global() + entries with DefaultNetstreamDriver from rsyslog.d/*.conf + ansible.builtin.shell: | + find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $DefaultNetstreamDriver is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $DefaultNetstreamDriver is configured correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} gtls$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + - name: Ensure Rsyslog Encrypts Off-Loaded Audit Records block: - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: false regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' state: absent - name: Check if /etc/rsyslog.d exists - stat: + ansible.builtin.stat: path: /etc/rsyslog.d register: _etc_rsyslog_d_exists - name: Check if the parameter $DefaultNetstreamDriver is present in /etc/rsyslog.d - find: + ansible.builtin.find: paths: /etc/rsyslog.d recurse: 'yes' follow: 'no' @@ -50201,7 +57564,7 @@ fi when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' create: false regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' @@ -50210,7 +57573,7 @@ fi when: _etc_rsyslog_d_has_parameter.matched - name: Insert correct line to /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: true regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' @@ -50219,6 +57582,7 @@ fi when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005025 - NIST-800-53-AU-4(1) @@ -50264,12 +57628,9 @@ correct this: DSS05.04 DSS05.07 DSS06.02 - CCI-001314 4.3.3.7.3 SR 2.1 SR 5.2 - 0988 - 1405 A.10.1.1 A.11.1.4 A.11.1.5 @@ -50293,15 +57654,15 @@ correct this: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 @@ -50309,6 +57670,8 @@ correct this: Req-10.5.1 Req-10.5.2 R71 + 0988 + 1405 10.3.2 10.3 The log files generated by rsyslog contain valuable information regarding system @@ -50694,12 +58057,9 @@ correct this: DSS05.04 DSS05.07 DSS06.02 - CCI-001314 4.3.3.7.3 SR 2.1 SR 5.2 - 0988 - 1405 A.10.1.1 A.11.1.4 A.11.1.5 @@ -50723,15 +58083,15 @@ correct this: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 @@ -50739,6 +58099,8 @@ correct this: Req-10.5.1 Req-10.5.2 R71 + 0988 + 1405 10.3.2 10.3 The log files generated by rsyslog contain valuable information regarding system @@ -51103,23 +58465,22 @@ If the permissions are not 640 or more restrictive, run the following command to correct this: $ sudo chmod 640 LOGFILE " - CCI-001314 - 0988 - 1405 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) Req-10.5.1 Req-10.5.2 R71 + 0988 + 1405 10.3.1 10.3 Log files can contain valuable information regarding system @@ -51485,11 +58846,10 @@ not, use the following as an example configuration: daemon.* /var/log/messages - CCI-000067 AC-17(1) - SRG-OS-000032-GPOS-00013 - OL09-00-005000 - SV-271851r1092265_rule + SRG-OS-000032-GPOS-00013 + OL09-00-005000 + SV-271851r1092265_rule Logging remote access methods can be used to trace the decrease the risks associated with remote user access management. It can also be used to spot cyber attacks and ensure ongoing compliance with organizational policies @@ -51540,7 +58900,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Set facts' - set_fact: + ansible.builtin.set_fact: conf_files: - /etc/rsyslog.conf remote_methods: @@ -51568,9 +58928,11 @@ fi - name: 'Ensure remote access methods are monitored in Rsyslog: Ensure rsyslog.conf exists' - file: + ansible.builtin.file: path: '{{ conf_files.0 }}' state: touch + access_time: preserve + modification_time: preserve when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -51585,7 +58947,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Gather conf.d files' - find: + ansible.builtin.find: patterns: - '*.conf' paths: @@ -51605,7 +58967,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Set conf file(s)' - set_fact: + ansible.builtin.set_fact: conf_files: '{{ conf_files + [item.path] }}' loop: '{{ rsyslogd.files }}' when: @@ -51624,7 +58986,7 @@ fi - name: 'Ensure remote access methods are monitored in Rsyslog: Check for existing values' - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.1 }}' regexp: '{{ item.0.regexp }}' state: absent @@ -51646,7 +59008,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Configure' - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf line: '{{ item.item.0.selector }} {{ item.item.0.location }}' insertafter: ^.*\/var\/log\/secure.*$ @@ -51691,11 +59053,10 @@ systemd. The systemd-journald service can be enabled with the following command: $ sudo systemctl enable systemd-journald.service - CCI-001665 SC-24 - SRG-OS-000269-GPOS-00103 - OL09-00-002400 - SV-271739r1091929_rule + SRG-OS-000269-GPOS-00103 + OL09-00-002400 + SV-271739r1091929_rule In the event of a system failure, Oracle Linux 9 must preserve any information necessary to determine cause of failure and any information necessary to return to operations with least disruption to system processes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -51728,7 +59089,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable systemd-journald Service - Enable Service systemd-journald @@ -51739,7 +59100,6 @@ fi masked: false when: - '"systemd" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002400 - NIST-800-53-SC-24 @@ -51749,6 +59109,8 @@ fi - medium_severity - no_reboot_needed - service_systemd-journald_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_systemd-journald @@ -51763,6 +59125,10 @@ class enable_systemd-journald { [customizations.services] enabled = ["systemd-journald"] + + + + @@ -51773,9 +59139,7 @@ enabled = ["systemd-journald"] Ensure All Logs are Rotated by logrotate - -Edit the file /etc/logrotate.d/syslog. Find the first - + Edit the file /etc/logrotate.d/syslog. Find the first line, which should look like this (wrapped for clarity): /var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \ /var/log/boot.log /var/log/cron { @@ -51813,7 +59177,6 @@ used. DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -51864,7 +59227,7 @@ fi - package_logrotate_installed - name: Ensure logrotate is installed - package: + ansible.builtin.package: name: logrotate state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -51924,7 +59287,6 @@ daily DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -51961,7 +59323,7 @@ CRON_DAILY_LOGROTATE_FILE="/etc/cron.daily/logrotate" # daily rotation is configured -grep -q "^daily$" $LOGROTATE_CONF_FILE|| echo "daily" >> $LOGROTATE_CONF_FILE +grep -q "^daily$" $LOGROTATE_CONF_FILE|| sed -i '1i daily' "$LOGROTATE_CONF_FILE" # remove any line configuring weekly, monthly or yearly rotation sed -i '/^\s*\(weekly\|monthly\|yearly\).*$/d' $LOGROTATE_CONF_FILE @@ -51991,11 +59353,13 @@ fi - no_reboot_needed - name: Configure daily log rotation in /etc/logrotate.conf - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/logrotate.conf - regexp: ^daily$ + regexp: ^\s*(weekly|monthly|yearly)$ line: daily + state: present + insertbefore: BOF when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"logrotate" in ansible_facts.packages' @@ -52009,8 +59373,8 @@ fi - medium_severity - no_reboot_needed -- name: Make sure daily log rotation setting is not overriden in /etc/logrotate.conf - lineinfile: +- name: Make sure daily log rotation setting is not overridden in /etc/logrotate.conf + ansible.builtin.lineinfile: create: false dest: /etc/logrotate.conf regexp: ^[\s]*(weekly|monthly|yearly)$ @@ -52032,17 +59396,18 @@ fi block: - name: Add shebang - lineinfile: + ansible.builtin.lineinfile: path: /etc/cron.daily/logrotate line: '#!/bin/sh' insertbefore: BOF create: true - name: Add logrotate call - lineinfile: + ansible.builtin.lineinfile: path: /etc/cron.daily/logrotate line: /usr/sbin/logrotate /etc/logrotate.conf regexp: ^[\s]*/usr/sbin/logrotate[\s\S]*/etc/logrotate.conf$ + create: true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"logrotate" in ansible_facts.packages' @@ -52081,7 +59446,6 @@ The logrotate timer can be enabled with the following com DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -52140,11 +59504,11 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable timer logrotate - systemd: + ansible.builtin.systemd: name: logrotate.timer enabled: 'yes' state: started @@ -52166,6 +59530,10 @@ fi - no_reboot_needed - timer_logrotate_enabled + + + + @@ -52204,8 +59572,6 @@ $ sudo yum install syslog-ng-core DSS05.04 DSS05.07 MEA02.01 - CCI-001311 - CCI-001312 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -52250,7 +59616,7 @@ fi - package_syslogng_installed - name: Ensure syslog-ng is installed - package: + ansible.builtin.package: name: syslog-ng state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -52326,10 +59692,6 @@ The syslog-ng service can be enabled with the following c MEA01.04 MEA01.05 MEA02.01 - CCI-001311 - CCI-001312 - CCI-001557 - CCI-001851 4.3.2.6.7 4.3.3.3.9 4.3.3.5.8 @@ -52397,7 +59759,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable syslog-ng Service - Enable Service syslog-ng @@ -52408,7 +59770,6 @@ fi masked: false when: - '"syslog-ng" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-4(1) - NIST-800-53-CM-6(a) @@ -52418,6 +59779,8 @@ fi - medium_severity - no_reboot_needed - service_syslogng_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_syslog-ng @@ -52432,6 +59795,10 @@ class enable_syslog-ng { [customizations.services] enabled = ["syslog-ng"] + + + + @@ -52476,12 +59843,12 @@ $InputTCPServerRun 514 A.12.4.3 A.12.4.4 A.12.7.1 - CIP-004-6 R2.2.2 - CIP-004-6 R3.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R6.5 + CIP-004-6 R2.2.2 + CIP-004-6 R3.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R6.5 CM-6(a) AU-6(3) AU-6(4) @@ -52526,12 +59893,12 @@ $UDPServerRun 514 A.12.4.3 A.12.4.4 A.12.7.1 - CIP-004-6 R2.2.2 - CIP-004-6 R3.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R6.5 + CIP-004-6 R2.2.2 + CIP-004-6 R3.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R6.5 CM-6(a) AU-6(3) AU-6(4) @@ -52591,7 +59958,6 @@ input(type="imudp" port="514") DSS05.07 DSS06.02 MEA02.01 - CCI-000366 4.2.3.4 4.3.3.3.9 4.3.3.4 @@ -52618,8 +59984,6 @@ input(type="imudp" port="514") SR 5.3 SR 7.1 SR 7.6 - 0988 - 1405 A.10.1.1 A.11.1.4 A.11.1.5 @@ -52667,9 +60031,11 @@ input(type="imudp" port="514") PR.IP-1 PR.PT-1 PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-005030 - SV-271857r1092283_rule + SRG-OS-000480-GPOS-00227 + 0988 + 1405 + OL09-00-005030 + SV-271857r1092283_rule Any process which receives messages from the network incurs some risk of receiving malicious messages. This risk can be eliminated for rsyslog by configuring it not to listen on the network. @@ -52991,14 +60357,23 @@ To use UDP for log message delivery: *.* @ +Or in RainerScript: +*.* action(type="omfwd" ... target="" protocol="udp") + To use TCP for log message delivery: *.* @@ +Or in RainerScript: +*.* action(type="omfwd" ... target="" protocol="tcp") + To use RELP for log message delivery: *.* :omrelp: +Or in RainerScript: +*.* action(type="omfwd" ... target="" protocol="relp") + There must be a resolvable DNS CNAME or Alias record set to "" for logs to be sent correctly to the centralized logging utility. It is important to configure queues in case the client is sending log messages to a remote server. If queues are not configured, @@ -53014,6 +60389,8 @@ $ActionQueueMaxDiskSpace 1g $ActionQueueSaveOnShutdown on $ActionResumeRetryCount -1 +Or if using Rainer Script syntax, it could be: +*.* action(type="omfwd" queue.type="linkedlist" queue.filename="example_fwd" action.resumeRetryCount="-1" queue.saveOnShutdown="on" target="example.com" port="30514" protocol="tcp") 1 13 @@ -53031,8 +60408,6 @@ $ActionResumeRetryCount -1 DSS05.04 DSS05.07 MEA02.01 - CCI-000366 - CCI-001851 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(B) 164.308(a)(5)(ii)(C) @@ -53055,8 +60430,6 @@ $ActionResumeRetryCount -1 SR 2.9 SR 7.1 SR 7.2 - 0988 - 1405 A.12.1.3 A.12.4.1 A.12.4.2 @@ -53064,19 +60437,21 @@ $ActionResumeRetryCount -1 A.12.4.4 A.12.7.1 A.17.2.1 - CIP-003-8 R5.2 - CIP-004-6 R3.3 + CIP-003-8 R5.2 + CIP-004-6 R3.3 CM-6(a) AU-4(1) AU-9(2) PR.DS-4 PR.PT-1 - SRG-OS-000479-GPOS-00224 - SRG-OS-000480-GPOS-00227 - SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + SRG-OS-000480-GPOS-00227 + SRG-OS-000342-GPOS-00133 R71 - OL09-00-005005 - SV-271852r1092608_rule + 0988 + 1405 + OL09-00-005005 + SV-271852r1092608_rule A log server (loghost) receives syslog messages from one or more systems. This data can be used as an additional log source in the event a system is compromised and its local logs are suspect. Forwarding log messages @@ -53133,7 +60508,7 @@ fi - always - name: Set rsyslog remote loghost - lineinfile: + ansible.builtin.lineinfile: dest: /etc/rsyslog.conf regexp: ^\*\.\* line: '*.* @@{{ rsyslog_remote_loghost_address }}' @@ -53168,13 +60543,13 @@ using action. You can use the following command: StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on")' >> /etc/rsyslog.conf Replace the <remote system> in the above command with an IP address or a host name of the remote logging server. - 0988 - 1405 AU-9(3) CM-6(a) - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 R71 + 0988 + 1405 For protection of data being logged, the connection to the remote logging server needs to be authenticated and encrypted. # Remediation is applicable only in certain platforms @@ -53433,10 +60808,10 @@ global option in /etc/rsyslog.conf, for example with the echo 'global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem")' >> /etc/rsyslog.conf Replace the /etc/pki/tls/cert.pem in the above command with the path to the file with CA certificate generated for the purpose of remote logging. Automatic remediation is not available as each organization has unique requirements. + SRG-OS-000480-GPOS-00227 + R71 0988 1405 - SRG-OS-000480-GPOS-00227 - R71 The CA certificate needs to be set or rsyslog.service fails to start with error: ca certificate is not set, cannot continue @@ -53499,7 +60874,6 @@ nameserver 192.168.0.2 8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -53516,9 +60890,9 @@ nameserver 192.168.0.2 SC-20(a) CM-6(a) PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-006003 - SV-271861r1092295_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006003 + SV-271861r1092295_rule To provide availability for name resolution services, multiple redundant name servers are mandated. A failure in name resolution could lead to the failure of security functions requiring name resolution, which may include @@ -53548,11 +60922,11 @@ ResultActive=auth_admin 3.1.16 + AC-18(4) + CM-6(a) 0418 1055 1402 - AC-18(4) - CM-6(a) 1.2.8 1.2 Allowing non-privileged users to make changes to network settings can allow @@ -53562,6 +60936,9 @@ attack. # Remediation is applicable only in certain platforms if rpm --quiet -q polkit; then +if ! rpm -q --quiet "polkit-pkla-compat" ; then + yum install -y "polkit-pkla-compat" +fi printf "[Disable General User Access to NetworkManager]\nIdentity=default\nAction=org.freedesktop.NetworkManager.*\nResultAny=no\nResultInactive=no\nResultActive=auth_admin\n" > /etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla else @@ -53584,8 +60961,28 @@ fi - no_reboot_needed - restrict_strategy -- name: Ensure non-privileged users do not have access to nmcli - ini_file: +- name: Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + - Ensure polkit-pkla-compat is installed + ansible.builtin.package: + name: polkit-pkla-compat + state: present + when: '"polkit" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(4) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - low_complexity + - low_disruption + - medium_severity + - network_nmcli_permissions + - no_reboot_needed + - restrict_strategy + +- name: Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + - Ensure non-privileged users do not have access to nmcli + community.general.ini_file: path: /etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla section: Disable General User Access to NetworkManager option: '{{ item.option }}' @@ -53653,7 +61050,6 @@ Promiscuous mode of an interface can be disabled with the following command: DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.2.3.4 4.3.3.3.7 4.3.3.5.1 @@ -53726,11 +61122,12 @@ Promiscuous mode of an interface can be disabled with the following command: PR.IP-1 PR.MA-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1409 1.4.5 1.4 - OL09-00-006004 - SV-271862r1092298_rule + OL09-00-006004 + SV-271862r1092298_rule Network interfaces in promiscuous mode allow for the capture of all network traffic visible to the system. If unauthorized individuals can access these applications, it may allow them to collect information such as logon IDs, passwords, and key exchanges @@ -53775,11 +61172,12 @@ fi - name: Ensure System is Not Acting as a Network Sniffer - Disable promiscuous mode ansible.builtin.command: - cmd: ip link set dev {{ item.split(':')[1] }} multicast off promisc off + cmd: ip link set dev {{ (item.split(':')[1] | trim).split('@')[0] }} multicast + off promisc off loop: '{{ network_interfaces.stdout_lines }}' when: - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - network_interfaces.stdout_lines is defined and "item.split(':') | length == 3" + - network_interfaces.stdout_lines is defined and item.split(':') | length >= 3 tags: - DISA-STIG-OL09-00-006004 - NIST-800-53-CM-6(a) @@ -53826,12 +61224,11 @@ the firewall has to be reloaded. Configure Firewalld to Use the Nftables Backend Firewalld can be configured with many backends, such as nftables. - CCI-002385 SC-5 - SRG-OS-000420-GPOS-00186 - OL09-00-006000 - SV-271858r1092286_rule - Nftables is modern kernel module for controling network connections coming into a system. + SRG-OS-000420-GPOS-00186 + OL09-00-006000 + SV-271858r1092286_rule + Nftables is modern kernel module for controlling network connections coming into a system. Utilizing the limit statement in "nftables" can help to mitigate DoS attacks. # Remediation is applicable only in certain platforms @@ -53883,7 +61280,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/firewalld/firewalld.conf create: true regexp: (?i)^\s*FirewallBackend= @@ -53893,7 +61290,7 @@ fi register: dupes - name: Deduplicate values from /etc/firewalld/firewalld.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/firewalld/firewalld.conf create: true regexp: (?i)^\s*FirewallBackend= @@ -53901,7 +61298,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/firewalld/firewalld.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/firewalld/firewalld.conf create: true regexp: (?i)^\s*FirewallBackend= @@ -54000,27 +61397,24 @@ service reload, enter the following command as root: $ sudo yum install firewalld - CCI-000382 - CCI-000366 - CCI-002314 - CCI-002322 CM-6(a) FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - SRG-OS-000298-GPOS-00116 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00232 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + SRG-OS-000298-GPOS-00116 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00232 A.8.SEC-OL3 + 1409 1.2.1 1.2 - OL09-00-000220 - SV-271469r1091119_rule + OL09-00-000220 + SV-271469r1091119_rule "Firewalld" provides an easy and effective way to block/limit remote access to the system via ports, services, and protocols. Remote access services, such as those providing remote access to network devices and information systems, which lack automated control capabilities, increase risk and make remote user access management difficult at best. -Remote access is access to DoD nonpublic information systems by an authorized user (or an information system) communicating through an external, non-organization-controlled network. Remote access methods include, for example, dial-up, broadband, and wireless. +Remote access is access to nonpublic information systems by an authorized user (or an information system) communicating through an external, non-organization-controlled network. Remote access methods include, for example, dial-up, broadband, and wireless. Oracle Linux 9 functionality (e.g., SSH) must be capable of taking enforcement action if the audit reveals unauthorized activity. Automated control of remote access sessions allows organizations to ensure ongoing compliance with remote access policies by enforcing connection rules of remote access applications on a variety of information system components (e.g., servers, workstations, notebook computers, smartphones, and tablets)." @@ -54051,7 +61445,7 @@ fi - package_firewalld_installed - name: Ensure firewalld is installed - package: + ansible.builtin.package: name: firewalld state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -54105,9 +61499,6 @@ The firewalld service can be enabled with the following c BAI10.05 3.1.3 3.4.7 - CCI-000382 - CCI-000366 - CCI-002314 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -54117,9 +61508,9 @@ The firewalld service can be enabled with the following c A.14.2.2 A.14.2.3 A.14.2.4 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 AC-4 CM-7(b) CA-3(5) @@ -54127,18 +61518,19 @@ The firewalld service can be enabled with the following c CM-6(a) PR.IP-1 FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00231 - SRG-OS-000480-GPOS-00232 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00231 + SRG-OS-000480-GPOS-00232 SYS.1.6.A5 SYS.1.6.A21 A.8.SEC-OL3 + 1409 1.2.1 1.2 - OL09-00-000221 - SV-271470r1092618_rule + OL09-00-000221 + SV-271470r1092618_rule Access control methods provide the ability to enhance system security posture by restricting services and known good IP addresses and address ranges. This prevents connections from unknown hosts and protocols. @@ -54182,7 +61574,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Verify firewalld Enabled - Enable Service firewalld @@ -54193,9 +61585,6 @@ fi masked: false when: - '"firewalld" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - '"firewalld" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000221 - NIST-800-171-3.1.3 @@ -54213,6 +61602,10 @@ fi - medium_severity - no_reboot_needed - service_firewalld_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"firewalld" in ansible_facts.packages' include enable_firewalld @@ -54227,6 +61620,10 @@ class enable_firewalld { [customizations.services] enabled = ["firewalld"] + + + + @@ -54283,8 +61680,6 @@ command: DSS05.03 DSS05.05 DSS06.06 - CCI-000382 - CCI-002314 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -54338,7 +61733,6 @@ command: SR 5.3 SR 7.1 SR 7.6 - 1416 A.11.2.6 A.12.1.2 A.12.5.1 @@ -54361,12 +61755,15 @@ command: PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + 1416 1.3.1 1.3 - OL09-00-000223 - SV-271472r1091128_rule + OL09-00-000223 + OL09-00-000222 + SV-271472r1091128_rule + SV-271471r1091125_rule In order to prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information @@ -54394,11 +61791,10 @@ conduct official business. Oracle Linux 9 incorporates the "firewalld" daemon, which allows for many different configurations. One of these configurations is zones. Zones can be utilized to a deny-all, allow-by-exception approach. The default "drop" zone will drop all incoming network packets unless it is explicitly allowed by the configuration file or is related to an outgoing network connection. - CCI-000366 AC-17 (1) - SRG-OS-000297-GPOS-00115 - OL09-00-000224 - SV-271473r1091131_rule + SRG-OS-000297-GPOS-00115 + OL09-00-000224 + SV-271473r1091131_rule Failure to restrict network connectivity only to authorized systems permits inbound connections from malicious systems. It also permits outbound connections that may facilitate exfiltration of data. @@ -54441,7 +61837,7 @@ fi ipv4_rule='rule family=ipv4 source address="127.0.0.1" destination not address="127.0.0.1" drop' ipv6_rule='rule family=ipv6 source address="::1" destination not address="::1" drop' -if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then firewall-offline-cmd --zone=trusted --add-rich-rule="${ipv4_rule}" firewall-offline-cmd --zone=trusted --add-rich-rule="${ipv6_rule}" elif systemctl is-active firewalld; then @@ -54552,7 +61948,7 @@ fi on Service State ansible.builtin.assert: that: - - ansible_facts.services['firewalld.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['firewalld.service'].state == 'running' fail_msg: - firewalld service is not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld service @@ -54604,7 +62000,7 @@ if ! rpm -q --quiet "firewalld" ; then yum install -y "firewalld" fi -if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then firewall-offline-cmd --zone=trusted --add-interface=lo elif systemctl is-active firewalld; then firewall-cmd --permanent --zone=trusted --add-interface=lo @@ -54654,7 +62050,6 @@ fi - name: Configure Firewalld to Trust Loopback Traffic - Collect Facts About System Services ansible.builtin.service_facts: null - register: result_services_states when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-1.4 @@ -54702,7 +62097,7 @@ fi on Service State ansible.builtin.assert: that: - - ansible_facts.services['firewalld.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['firewalld.service'].state == 'running' fail_msg: - firewalld service is not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld service @@ -54756,7 +62151,6 @@ above. 3.1.3 3.4.7 3.13.6 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -54801,7 +62195,6 @@ above. SR 2.6 SR 2.7 SR 7.6 - 1416 A.12.1.2 A.12.5.1 A.12.6.2 @@ -54816,8 +62209,9 @@ above. PR.IP-1 PR.PT-3 Req-1.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL3 + 1416 1.3.1 1.3 In firewalld the default zone is applied only after all @@ -54857,8 +62251,6 @@ $ sudo yum install libreswan DSS05.02 DSS05.03 DSS05.04 - CCI-000366 - CCI-000803 4.3.3.6.5 4.3.3.6.6 4.3.3.6.7 @@ -54889,22 +62281,44 @@ $ sudo yum install libreswan PR.MA-2 PR.PT-4 Req-4.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 - OL09-00-000410 - SV-271517r1091263_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 + OL09-00-000410 + SV-271517r1101885_rule Providing the ability for remote users or systems to initiate a secure VPN connection protects information when it is transmitted over a wide area network. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if ! rpm -q --quiet "libreswan" ; then yum install -y "libreswan" fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure libreswan is installed - package: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000410 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-4.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_libreswan_installed + +- name: Ensure libreswan is installed + ansible.builtin.package: name: libreswan state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000410 - NIST-800-53-CM-6(a) @@ -54941,7 +62355,8 @@ version = "*" Verify Group Who Owns /etc/ipsec.d Directory - To properly set the group owner of /etc/ipsec.d, run the command: $ sudo chgrp root /etc/ipsec.d + To properly set the group owner of /etc/ipsec.d, run the command: +$ sudo chgrp root /etc/ipsec.d R50 The ownership of the /etc/ipsec.d directory by the root group is important @@ -54952,7 +62367,17 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -find -H /etc/ipsec.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/ipsec.d/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -54969,11 +62394,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"libreswan" in ansible_facts.packages' + - directory_groupowner_etc_ipsecd_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_ipsecd_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_ipsecd_newgroup: root + when: + - '"libreswan" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/ipsec.d/ - file: + ansible.builtin.file: path: /etc/ipsec.d/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_ipsecd_newgroup }}' when: '"libreswan" in ansible_facts.packages' tags: - configure_strategy @@ -54992,7 +62448,8 @@ fi Verify User Who Owns /etc/ipsec.d Directory - To properly set the owner of /etc/ipsec.d, run the command: $ sudo chown root /etc/ipsec.d + To properly set the owner of /etc/ipsec.d, run the command: +$ sudo chown root /etc/ipsec.d R50 The ownership of the /etc/ipsec.d directory by the root user is important @@ -55003,7 +62460,17 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -find -H /etc/ipsec.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/ipsec.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55020,11 +62487,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_ipsecd_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_ipsecd_newown: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/ipsec.d/ - file: + ansible.builtin.file: path: /etc/ipsec.d/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_ipsecd_newown }}' when: '"libreswan" in ansible_facts.packages' tags: - configure_strategy @@ -55054,7 +62534,7 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -find -H /etc/ipsec.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/ipsec.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55072,7 +62552,8 @@ fi - no_reboot_needed - name: Find /etc/ipsec.d/ file(s) - command: 'find -H /etc/ipsec.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/ipsec.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -55087,7 +62568,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/ipsec.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -55111,7 +62592,8 @@ fi Verify Group Who Owns /etc/ipsec.conf File - To properly set the group owner of /etc/ipsec.conf, run the command: $ sudo chgrp root /etc/ipsec.conf + To properly set the group owner of /etc/ipsec.conf, run the command: +$ sudo chgrp root /etc/ipsec.conf R50 The ownership of the /etc/ipsec.conf file by the root group is important @@ -55122,7 +62604,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chgrp root /etc/ipsec.conf +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/ipsec.conf" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/ipsec.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55139,8 +62633,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"libreswan" in ansible_facts.packages' + - file_groupowner_etc_ipsec_conf_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_ipsec_conf_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_ipsec_conf_newgroup: root + when: + - '"libreswan" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.conf - stat: + ansible.builtin.stat: path: /etc/ipsec.conf register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55152,10 +62676,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/ipsec.conf - file: +- name: Ensure group owner on /etc/ipsec.conf + ansible.builtin.file: path: /etc/ipsec.conf - group: root + follow: false + group: '{{ file_groupowner_etc_ipsec_conf_newgroup }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55176,7 +62701,8 @@ fi Verify Group Who Owns /etc/ipsec.secrets File - To properly set the group owner of /etc/ipsec.secrets, run the command: $ sudo chgrp root /etc/ipsec.secrets + To properly set the group owner of /etc/ipsec.secrets, run the command: +$ sudo chgrp root /etc/ipsec.secrets R50 The ownership of the /etc/ipsec.secrets file by the root group is important @@ -55187,7 +62713,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chgrp root /etc/ipsec.secrets +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/ipsec.secrets" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/ipsec.secrets +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55204,8 +62742,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"libreswan" in ansible_facts.packages' + - file_groupowner_etc_ipsec_secrets_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_ipsec_secrets_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_ipsec_secrets_newgroup: root + when: + - '"libreswan" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.secrets - stat: + ansible.builtin.stat: path: /etc/ipsec.secrets register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55217,10 +62785,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/ipsec.secrets - file: +- name: Ensure group owner on /etc/ipsec.secrets + ansible.builtin.file: path: /etc/ipsec.secrets - group: root + follow: false + group: '{{ file_groupowner_etc_ipsec_secrets_newgroup }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55241,7 +62810,8 @@ fi Verify User Who Owns /etc/ipsec.conf File - To properly set the owner of /etc/ipsec.conf, run the command: $ sudo chown root /etc/ipsec.conf + To properly set the owner of /etc/ipsec.conf, run the command: +$ sudo chown root /etc/ipsec.conf R50 The ownership of the /etc/ipsec.conf file by the root user is important @@ -55252,7 +62822,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chown 0 /etc/ipsec.conf +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/ipsec.conf" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/ipsec.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55269,8 +62851,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_ipsec_conf_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_ipsec_conf_newown: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_owner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.conf - stat: + ansible.builtin.stat: path: /etc/ipsec.conf register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55282,10 +62876,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/ipsec.conf - file: +- name: Ensure owner on /etc/ipsec.conf + ansible.builtin.file: path: /etc/ipsec.conf - owner: '0' + follow: false + owner: '{{ file_owner_etc_ipsec_conf_newown }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55306,7 +62901,8 @@ fi Verify User Who Owns /etc/ipsec.secrets File - To properly set the owner of /etc/ipsec.secrets, run the command: $ sudo chown root /etc/ipsec.secrets + To properly set the owner of /etc/ipsec.secrets, run the command: +$ sudo chown root /etc/ipsec.secrets R50 The ownership of the /etc/ipsec.secrets file by the root user is important @@ -55317,7 +62913,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chown 0 /etc/ipsec.secrets +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/ipsec.secrets" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/ipsec.secrets +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55334,8 +62942,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_ipsec_secrets_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_ipsec_secrets_newown: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_owner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.secrets - stat: + ansible.builtin.stat: path: /etc/ipsec.secrets register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55347,10 +62967,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/ipsec.secrets - file: +- name: Ensure owner on /etc/ipsec.secrets + ansible.builtin.file: path: /etc/ipsec.secrets - owner: '0' + follow: false + owner: '{{ file_owner_etc_ipsec_secrets_newown }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55400,7 +63021,7 @@ fi - no_reboot_needed - name: Test for existence /etc/ipsec.conf - stat: + ansible.builtin.stat: path: /etc/ipsec.conf register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55413,7 +63034,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/ipsec.conf - file: + ansible.builtin.file: path: /etc/ipsec.conf mode: u-xs,g-xws,o-xwt when: @@ -55465,7 +63086,7 @@ fi - no_reboot_needed - name: Test for existence /etc/ipsec.secrets - stat: + ansible.builtin.stat: path: /etc/ipsec.secrets register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55478,7 +63099,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/ipsec.secrets - file: + ansible.builtin.file: path: /etc/ipsec.secrets mode: u-xs,g-xws,o-xwt when: @@ -55528,7 +63149,6 @@ requirements of each system. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -55585,10 +63205,11 @@ requirements of each system. PR.AC-5 PR.DS-5 PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-006010 - SV-271863r1092639_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006010 + SV-271863r1092639_rule IP tunneling mechanisms can be used to bypass network filtering. + @@ -55618,7 +63239,8 @@ sophisticated ruleset tailored to your environment, please consult the references at the end of this section. Verify Group Who Owns /etc/iptables Directory - To properly set the group owner of /etc/iptables, run the command: $ sudo chgrp root /etc/iptables + To properly set the group owner of /etc/iptables, run the command: +$ sudo chgrp root /etc/iptables R50 The ownership of the /etc/iptables directory by the root group is important @@ -55629,7 +63251,17 @@ ensures exclusive control of the iptables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q iptables; then -find -H /etc/iptables/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/iptables/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55646,11 +63278,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"iptables" in ansible_facts.packages' + - directory_groupowner_etc_iptables_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_iptables_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_iptables_newgroup: root + when: + - '"iptables" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/iptables/ - file: + ansible.builtin.file: path: /etc/iptables/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_iptables_newgroup }}' when: '"iptables" in ansible_facts.packages' tags: - configure_strategy @@ -55669,7 +63332,8 @@ fi Verify User Who Owns /etc/iptables Directory - To properly set the owner of /etc/iptables, run the command: $ sudo chown root /etc/iptables + To properly set the owner of /etc/iptables, run the command: +$ sudo chown root /etc/iptables R50 The ownership of the /etc/iptables directory by the root user is important @@ -55680,7 +63344,17 @@ ensures exclusive control of the iptables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q iptables; then -find -H /etc/iptables/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/iptables/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55697,11 +63371,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_iptables_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_iptables_newown: '0' + when: '"iptables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/iptables/ - file: + ansible.builtin.file: path: /etc/iptables/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_iptables_newown }}' when: '"iptables" in ansible_facts.packages' tags: - configure_strategy @@ -55731,7 +63418,7 @@ ensures exclusive control of the iptables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q iptables; then -find -H /etc/iptables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/iptables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55749,7 +63436,8 @@ fi - no_reboot_needed - name: Find /etc/iptables/ file(s) - command: 'find -H /etc/iptables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/iptables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -55764,7 +63452,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/iptables/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -55935,9 +63623,9 @@ The iptables service can be enabled with the following co A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 AC-4 CM-7(b) CA-3(5) @@ -55954,7 +63642,7 @@ The iptables service can be enabled with the following co capability for IPv4 and ICMP. # Remediation is applicable only in certain platforms -if ( rpm --quiet -q iptables && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then +if ( rpm --quiet -q iptables && ! (systemctl is-active firewalld &>/dev/null) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'iptables.service' @@ -55987,7 +63675,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Verify iptables Enabled - Enable Service iptables @@ -55998,8 +63686,6 @@ fi masked: false when: - '"iptables" in ansible_facts.packages' - when: ( "iptables" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) tags: - NIST-800-53-AC-4 - NIST-800-53-CA-3(5) @@ -56012,6 +63698,9 @@ fi - medium_severity - no_reboot_needed - service_iptables_enabled + - special_service_block + when: ( "iptables" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) include enable_iptables @@ -56026,6 +63715,10 @@ class enable_iptables { [customizations.services] enabled = ["iptables"] + + + + @@ -56107,9 +63800,9 @@ If changes were required, reload the ip6tables rules: A.14.2.3 A.14.2.4 A.9.1.2 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 AC-4 CM-7(b) CA-3(5) @@ -56134,6 +63827,10 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi + + + + @@ -56177,7 +63874,9 @@ saved configuration file. To set the default policy to DROP (instead of ACCEPT) for the built-in INPUT chain which processes incoming packets, add or correct the following line in + /etc/sysconfig/iptables: + :INPUT DROP [0:0] 11 @@ -56505,7 +64204,7 @@ fi - reboot_required - name: Disable IPv6 Networking kernel module - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/ipv6.conf regexp: ^options\s+ipv6\s+disable=\d @@ -56523,7 +64222,7 @@ fi - reboot_required - name: Ensure disable_ipv6 (all and default) is set to 1 - sysctl: + ansible.posix.sysctl: name: '{{ item }}' value: '1' state: present @@ -56569,7 +64268,6 @@ functionality require the IPv6 stack loaded to work. DSS05.05 DSS06.06 3.1.20 - CCI-001551 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -56660,7 +64358,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv6.conf.all.disable_ipv6 # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv6.conf.all.disable_ipv6="1" fi @@ -56708,16 +64406,12 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.disable_ipv6.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.20 @@ -56731,14 +64425,61 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 -- name: Comment out any occurrences of net.ipv6.conf.all.disable_ipv6 from config - files - replace: - path: '{{ item.path }}' +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Find all files that contain + net.ipv6.conf.all.disable_ipv6 + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.disable_ipv6\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Find all files that set net.ipv6.conf.all.disable_ipv6 + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.disable_ipv6\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Comment out any occurrences + of net.ipv6.conf.all.disable_ipv6 from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv6.conf.all.disable_ipv6 replace: '#net.ipv6.conf.all.disable_ipv6' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-171-3.1.20 - NIST-800-53-CM-6(a) @@ -56751,8 +64492,9 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 -- name: Ensure sysctl net.ipv6.conf.all.disable_ipv6 is set to 1 - sysctl: +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Ensure sysctl net.ipv6.conf.all.disable_ipv6 + is set to 1 + ansible.posix.sysctl: name: net.ipv6.conf.all.disable_ipv6 value: '1' sysctl_file: /etc/sysctl.conf @@ -56771,6 +64513,10 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 + + + + @@ -56797,7 +64543,6 @@ functionality require the IPv6 stack loaded to work. DSS05.05 DSS06.06 3.1.20 - CCI-001551 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -56888,7 +64633,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv6.conf.default.disable_ipv6 # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv6.conf.default.disable_ipv6="1" fi @@ -56936,16 +64681,13 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.disable_ipv6.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.20 @@ -56959,14 +64701,61 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 -- name: Comment out any occurrences of net.ipv6.conf.default.disable_ipv6 from config - files - replace: - path: '{{ item.path }}' +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Find all files that + contain net.ipv6.conf.default.disable_ipv6 + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.disable_ipv6\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Find all files that + set net.ipv6.conf.default.disable_ipv6 to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.disable_ipv6\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Comment out any occurrences + of net.ipv6.conf.default.disable_ipv6 from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv6.conf.default.disable_ipv6 replace: '#net.ipv6.conf.default.disable_ipv6' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-171-3.1.20 - NIST-800-53-CM-6(a) @@ -56979,8 +64768,9 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 -- name: Ensure sysctl net.ipv6.conf.default.disable_ipv6 is set to 1 - sysctl: +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Ensure sysctl net.ipv6.conf.default.disable_ipv6 + is set to 1 + ansible.posix.sysctl: name: net.ipv6.conf.default.disable_ipv6 value: '1' sysctl_file: /etc/sysctl.conf @@ -56999,6 +64789,10 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 + + + + @@ -57166,7 +64960,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -57223,10 +65016,10 @@ To make sure that the setting is persistent, add the following line to a file in CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006040 - SV-271877r1092343_rule + OL09-00-006040 + SV-271877r1092343_rule An illicit router advertisement message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -57262,7 +65055,7 @@ sysctl_net_ipv6_conf_all_accept_ra_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra is set - sysctl: +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Find all + files that contain net.ipv6.conf.all.accept_ra + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Find all + files that set net.ipv6.conf.all.accept_ra to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Comment + out any occurrences of net.ipv6.conf.all.accept_ra from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra + replace: '#net.ipv6.conf.all.accept_ra' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Ensure + sysctl net.ipv6.conf.all.accept_ra is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra value: '{{ sysctl_net_ipv6_conf_all_accept_ra_value }}' sysctl_file: /etc/sysctl.conf @@ -57381,6 +65223,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_accept_ra + + + + + @@ -57430,7 +65277,7 @@ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_defrtr is set - sysctl: +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Find all files that contain net.ipv6.conf.all.accept_ra_defrtr + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_defrtr\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Find all files that set net.ipv6.conf.all.accept_ra_defrtr to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_defrtr\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.all.accept_ra_defrtr from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_defrtr + replace: '#net.ipv6.conf.all.accept_ra_defrtr' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.all.accept_ra_defrtr is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra_defrtr value: '{{ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value }}' sysctl_file: /etc/sysctl.conf @@ -57530,6 +65416,11 @@ fi - sysctl_net_ipv6_conf_all_accept_ra_defrtr - unknown_severity + + + + + @@ -57579,7 +65470,7 @@ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_pinfo is set - sysctl: +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Find all files that contain net.ipv6.conf.all.accept_ra_pinfo + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_pinfo\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Find all files that set net.ipv6.conf.all.accept_ra_pinfo to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_pinfo\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Comment out any occurrences of net.ipv6.conf.all.accept_ra_pinfo + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_pinfo + replace: '#net.ipv6.conf.all.accept_ra_pinfo' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Ensure sysctl net.ipv6.conf.all.accept_ra_pinfo is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra_pinfo value: '{{ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value }}' sysctl_file: /etc/sysctl.conf @@ -57679,6 +65610,11 @@ fi - sysctl_net_ipv6_conf_all_accept_ra_pinfo - unknown_severity + + + + + @@ -57728,7 +65664,7 @@ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_rtr_pref is set - sysctl: +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Find all files that contain net.ipv6.conf.all.accept_ra_rtr_pref + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_rtr_pref\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Find all files that set net.ipv6.conf.all.accept_ra_rtr_pref to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_rtr_pref\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Comment out any occurrences of net.ipv6.conf.all.accept_ra_rtr_pref + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref + replace: '#net.ipv6.conf.all.accept_ra_rtr_pref' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Ensure sysctl net.ipv6.conf.all.accept_ra_rtr_pref is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra_rtr_pref value: '{{ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value }}' sysctl_file: /etc/sysctl.conf @@ -57828,6 +65804,11 @@ fi - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref - unknown_severity + + + + + @@ -57853,7 +65834,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -57912,11 +65892,11 @@ To make sure that the setting is persistent, add the following line to a file in CM-6.1(iv) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 - OL09-00-006041 - SV-271878r1092346_rule + OL09-00-006041 + SV-271878r1092346_rule An illicit ICMP redirect message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -57952,7 +65932,7 @@ sysctl_net_ipv6_conf_all_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_redirects is set - sysctl: +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Find all files + that contain net.ipv6.conf.all.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Find all files + that set net.ipv6.conf.all.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_redirects\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Comment out any + occurrences of net.ipv6.conf.all.accept_redirects from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_redirects + replace: '#net.ipv6.conf.all.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Ensure sysctl net.ipv6.conf.all.accept_redirects + is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_redirects value: '{{ sysctl_net_ipv6_conf_all_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -58080,6 +66112,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_accept_redirects + + + + + @@ -58113,7 +66150,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -58162,11 +66198,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.AC-5 PR.DS-5 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 - OL09-00-006042 - SV-271879r1092349_rule + OL09-00-006042 + SV-271879r1092349_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the @@ -58210,7 +66246,7 @@ sysctl_net_ipv6_conf_all_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Find all files that contain net.ipv6.conf.all.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Find all files that set net.ipv6.conf.all.accept_source_route to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_source_route\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.all.accept_source_route from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_source_route + replace: '#net.ipv6.conf.all.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.all.accept_source_route is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_source_route value: '{{ sysctl_net_ipv6_conf_all_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -58330,6 +66415,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_accept_source_route + + + + + @@ -58379,7 +66469,7 @@ sysctl_net_ipv6_conf_all_autoconf_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.autoconf is set - sysctl: +- name: Configure Auto Configuration on All IPv6 Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Find all files that + contain net.ipv6.conf.all.autoconf + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.autoconf\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Find all files that + set net.ipv6.conf.all.autoconf to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.autoconf\s*=\s*{{ sysctl_net_ipv6_conf_all_autoconf_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Comment out any occurrences + of net.ipv6.conf.all.autoconf from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.autoconf + replace: '#net.ipv6.conf.all.autoconf' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Ensure sysctl net.ipv6.conf.all.autoconf + is set + ansible.posix.sysctl: name: net.ipv6.conf.all.autoconf value: '{{ sysctl_net_ipv6_conf_all_autoconf_value }}' sysctl_file: /etc/sysctl.conf @@ -58478,6 +66607,11 @@ fi - sysctl_net_ipv6_conf_all_autoconf - unknown_severity + + + + + @@ -58515,7 +66649,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS05.07 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -58581,9 +66714,9 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-4 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-006043 - SV-271880r1092352_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006043 + SV-271880r1092352_rule IP forwarding permits the kernel to forward packets from one network interface to another. The ability to forward packets between two networks is only appropriate for systems acting as routers. @@ -58621,7 +66754,7 @@ sysctl_net_ipv6_conf_all_forwarding_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.forwarding is set - sysctl: +- name: Disable Kernel Parameter for IPv6 Forwarding - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Find all files that contain + net.ipv6.conf.all.forwarding + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.forwarding\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Find all files that set net.ipv6.conf.all.forwarding + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.forwarding\s*=\s*{{ sysctl_net_ipv6_conf_all_forwarding_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Comment out any occurrences + of net.ipv6.conf.all.forwarding from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.forwarding + replace: '#net.ipv6.conf.all.forwarding' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Ensure sysctl net.ipv6.conf.all.forwarding + is set + ansible.posix.sysctl: name: net.ipv6.conf.all.forwarding value: '{{ sysctl_net_ipv6_conf_all_forwarding_value }}' sysctl_file: /etc/sysctl.conf @@ -58744,6 +66927,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_forwarding + + + + + @@ -58793,7 +66981,7 @@ sysctl_net_ipv6_conf_all_max_addresses_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.max_addresses is set - sysctl: +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Find all files that contain net.ipv6.conf.all.max_addresses + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.max_addresses\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Find all files that set net.ipv6.conf.all.max_addresses to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.max_addresses\s*=\s*{{ sysctl_net_ipv6_conf_all_max_addresses_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.all.max_addresses from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.max_addresses + replace: '#net.ipv6.conf.all.max_addresses' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.all.max_addresses is set + ansible.posix.sysctl: name: net.ipv6.conf.all.max_addresses value: '{{ sysctl_net_ipv6_conf_all_max_addresses_value }}' sysctl_file: /etc/sysctl.conf @@ -58893,6 +67119,11 @@ fi - sysctl_net_ipv6_conf_all_max_addresses - unknown_severity + + + + + @@ -58942,7 +67173,7 @@ sysctl_net_ipv6_conf_all_router_solicitations_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.router_solicitations is set - sysctl: +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Set fact for + sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Find all files + that contain net.ipv6.conf.all.router_solicitations + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.router_solicitations\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Find all files + that set net.ipv6.conf.all.router_solicitations to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.router_solicitations\s*=\s*{{ sysctl_net_ipv6_conf_all_router_solicitations_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Comment out + any occurrences of net.ipv6.conf.all.router_solicitations from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.router_solicitations + replace: '#net.ipv6.conf.all.router_solicitations' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Ensure sysctl + net.ipv6.conf.all.router_solicitations is set + ansible.posix.sysctl: name: net.ipv6.conf.all.router_solicitations value: '{{ sysctl_net_ipv6_conf_all_router_solicitations_value }}' sysctl_file: /etc/sysctl.conf @@ -59042,6 +67311,11 @@ fi - sysctl_net_ipv6_conf_all_router_solicitations - unknown_severity + + + + + @@ -59067,7 +67341,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -59124,10 +67397,10 @@ To make sure that the setting is persistent, add the following line to a file in CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006044 - SV-271881r1092355_rule + OL09-00-006044 + SV-271881r1092355_rule An illicit router advertisement message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -59163,7 +67436,7 @@ sysctl_net_ipv6_conf_default_accept_ra_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra is set - sysctl: +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Find all files that contain net.ipv6.conf.default.accept_ra + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Find all files that set net.ipv6.conf.default.accept_ra to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Comment out any occurrences of net.ipv6.conf.default.accept_ra from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra + replace: '#net.ipv6.conf.default.accept_ra' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Ensure sysctl net.ipv6.conf.default.accept_ra is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra value: '{{ sysctl_net_ipv6_conf_default_accept_ra_value }}' sysctl_file: /etc/sysctl.conf @@ -59283,6 +67604,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_accept_ra + + + + + @@ -59332,7 +67658,7 @@ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_defrtr is set - sysctl: +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Find all files that contain net.ipv6.conf.default.accept_ra_defrtr + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_defrtr\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Find all files that set net.ipv6.conf.default.accept_ra_defrtr to + correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_defrtr\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Comment out any occurrences of net.ipv6.conf.default.accept_ra_defrtr + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_defrtr + replace: '#net.ipv6.conf.default.accept_ra_defrtr' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Ensure sysctl net.ipv6.conf.default.accept_ra_defrtr is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra_defrtr value: '{{ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value }}' sysctl_file: /etc/sysctl.conf @@ -59432,6 +67798,11 @@ fi - sysctl_net_ipv6_conf_default_accept_ra_defrtr - unknown_severity + + + + + @@ -59481,7 +67852,7 @@ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_pinfo is set - sysctl: +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that contain net.ipv6.conf.default.accept_ra_pinfo + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_pinfo\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that set net.ipv6.conf.default.accept_ra_pinfo + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_pinfo\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Comment out any occurrences of net.ipv6.conf.default.accept_ra_pinfo + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_pinfo + replace: '#net.ipv6.conf.default.accept_ra_pinfo' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Ensure sysctl net.ipv6.conf.default.accept_ra_pinfo is + set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra_pinfo value: '{{ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value }}' sysctl_file: /etc/sysctl.conf @@ -59581,6 +67993,11 @@ fi - sysctl_net_ipv6_conf_default_accept_ra_pinfo - unknown_severity + + + + + @@ -59630,7 +68047,7 @@ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_rtr_pref is set - sysctl: +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that contain net.ipv6.conf.default.accept_ra_rtr_pref + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_rtr_pref\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that set net.ipv6.conf.default.accept_ra_rtr_pref + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_rtr_pref\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Comment out any occurrences of net.ipv6.conf.default.accept_ra_rtr_pref + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref + replace: '#net.ipv6.conf.default.accept_ra_rtr_pref' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Ensure sysctl net.ipv6.conf.default.accept_ra_rtr_pref + is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra_rtr_pref value: '{{ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value }}' sysctl_file: /etc/sysctl.conf @@ -59730,6 +68188,11 @@ fi - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref - unknown_severity + + + + + @@ -59755,7 +68218,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -59812,11 +68274,11 @@ To make sure that the setting is persistent, add the following line to a file in CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 - OL09-00-006045 - SV-271882r1092358_rule + OL09-00-006045 + SV-271882r1092358_rule An illicit ICMP redirect message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -59852,7 +68314,7 @@ sysctl_net_ipv6_conf_default_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_redirects is set - sysctl: +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Find all files that contain net.ipv6.conf.default.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Find all files that set net.ipv6.conf.default.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_redirects\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.default.accept_redirects from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_redirects + replace: '#net.ipv6.conf.default.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.default.accept_redirects is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_redirects value: '{{ sysctl_net_ipv6_conf_default_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -59972,6 +68483,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_accept_redirects + + + + + @@ -60005,7 +68521,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -60057,13 +68572,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-5 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 1.4.2 1.4 - OL09-00-006046 - SV-271883r1092361_rule + OL09-00-006046 + SV-271883r1092361_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the @@ -60106,7 +68621,7 @@ sysctl_net_ipv6_conf_default_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Find all files that contain net.ipv6.conf.default.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Find all files that set net.ipv6.conf.default.accept_source_route + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_source_route\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Comment out any occurrences of net.ipv6.conf.default.accept_source_route + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_source_route + replace: '#net.ipv6.conf.default.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Ensure sysctl net.ipv6.conf.default.accept_source_route is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_source_route value: '{{ sysctl_net_ipv6_conf_default_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -60246,6 +68821,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_accept_source_route + + + + + @@ -60295,7 +68875,7 @@ sysctl_net_ipv6_conf_default_autoconf_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.autoconf is set - sysctl: +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Find all + files that contain net.ipv6.conf.default.autoconf + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.autoconf\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Find all + files that set net.ipv6.conf.default.autoconf to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.autoconf\s*=\s*{{ sysctl_net_ipv6_conf_default_autoconf_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Comment out + any occurrences of net.ipv6.conf.default.autoconf from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.autoconf + replace: '#net.ipv6.conf.default.autoconf' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Ensure sysctl + net.ipv6.conf.default.autoconf is set + ansible.posix.sysctl: name: net.ipv6.conf.default.autoconf value: '{{ sysctl_net_ipv6_conf_default_autoconf_value }}' sysctl_file: /etc/sysctl.conf @@ -60395,6 +69013,11 @@ fi - sysctl_net_ipv6_conf_default_autoconf - unknown_severity + + + + + @@ -60444,7 +69067,7 @@ sysctl_net_ipv6_conf_default_max_addresses_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.max_addresses is set - sysctl: +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Find all files that contain net.ipv6.conf.default.max_addresses + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.max_addresses\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Find all files that set net.ipv6.conf.default.max_addresses to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.max_addresses\s*=\s*{{ sysctl_net_ipv6_conf_default_max_addresses_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Comment out any occurrences of net.ipv6.conf.default.max_addresses + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.max_addresses + replace: '#net.ipv6.conf.default.max_addresses' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Ensure sysctl net.ipv6.conf.default.max_addresses is set + ansible.posix.sysctl: name: net.ipv6.conf.default.max_addresses value: '{{ sysctl_net_ipv6_conf_default_max_addresses_value }}' sysctl_file: /etc/sysctl.conf @@ -60544,6 +69207,11 @@ fi - sysctl_net_ipv6_conf_default_max_addresses - unknown_severity + + + + + @@ -60593,7 +69261,7 @@ sysctl_net_ipv6_conf_default_router_solicitations_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.router_solicitations is set - sysctl: +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Find all files that contain net.ipv6.conf.default.router_solicitations + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.router_solicitations\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Find all files that set net.ipv6.conf.default.router_solicitations to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.router_solicitations\s*=\s*{{ sysctl_net_ipv6_conf_default_router_solicitations_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Comment out any occurrences of net.ipv6.conf.default.router_solicitations from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.router_solicitations + replace: '#net.ipv6.conf.default.router_solicitations' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Ensure sysctl net.ipv6.conf.default.router_solicitations is set + ansible.posix.sysctl: name: net.ipv6.conf.default.router_solicitations value: '{{ sysctl_net_ipv6_conf_default_router_solicitations_value }}' sysctl_file: /etc/sysctl.conf @@ -60693,6 +69401,11 @@ fi - sysctl_net_ipv6_conf_default_router_solicitations - unknown_severity + + + + + @@ -60924,7 +69637,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.accept_local # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_local="0" fi @@ -60968,16 +69681,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Accepting Packets Routed Between Local Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.accept_local.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -60987,14 +69697,53 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local -- name: Comment out any occurrences of net.ipv4.conf.all.accept_local from config - files - replace: - path: '{{ item.path }}' +- name: Disable Accepting Packets Routed Between Local Interfaces - Find all files + that contain net.ipv4.conf.all.accept_local + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_local\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: Disable Accepting Packets Routed Between Local Interfaces - Find all files + that set net.ipv4.conf.all.accept_local to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_local\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: Disable Accepting Packets Routed Between Local Interfaces - Comment out any + occurrences of net.ipv4.conf.all.accept_local from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.accept_local replace: '#net.ipv4.conf.all.accept_local' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -61003,8 +69752,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local -- name: Ensure sysctl net.ipv4.conf.all.accept_local is set to 0 - sysctl: +- name: Disable Accepting Packets Routed Between Local Interfaces - Ensure sysctl + net.ipv4.conf.all.accept_local is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.all.accept_local value: '0' sysctl_file: /etc/sysctl.conf @@ -61019,6 +69769,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local + + + + @@ -61057,7 +69811,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -61122,11 +69875,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-4 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006020 - SV-271864r1092304_rule + OL09-00-006020 + SV-271864r1092304_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect @@ -61167,7 +69920,7 @@ sysctl_net_ipv4_conf_all_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.accept_redirects is set - sysctl: +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Find all files + that contain net.ipv4.conf.all.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Find all files + that set net.ipv4.conf.all.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_redirects\s*=\s*{{ sysctl_net_ipv4_conf_all_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Comment out any + occurrences of net.ipv4.conf.all.accept_redirects from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_redirects + replace: '#net.ipv4.conf.all.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Ensure sysctl net.ipv4.conf.all.accept_redirects + is set + ansible.posix.sysctl: name: net.ipv4.conf.all.accept_redirects value: '{{ sysctl_net_ipv4_conf_all_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -61295,6 +70100,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_redirects + + + + + @@ -61341,7 +70151,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -61434,10 +70243,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -61452,11 +70261,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006021 - SV-271865r1092307_rule + OL09-00-006021 + SV-271865r1092307_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement @@ -61499,7 +70308,7 @@ sysctl_net_ipv4_conf_all_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.accept_source_route to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_source_route\s*=\s*{{ sysctl_net_ipv4_conf_all_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.accept_source_route from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_source_route + replace: '#net.ipv4.conf.all.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.accept_source_route is set + ansible.posix.sysctl: name: net.ipv4.conf.all.accept_source_route value: '{{ sysctl_net_ipv4_conf_all_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -61627,6 +70489,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_source_route + + + + + @@ -61680,7 +70547,7 @@ sysctl_net_ipv4_conf_all_arp_filter_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.arp_filter is set - sysctl: +- name: Configure ARP filtering for All IPv4 Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Find all files that contain + net.ipv4.conf.all.arp_filter + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_filter\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Find all files that set + net.ipv4.conf.all.arp_filter to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_filter\s*=\s*{{ sysctl_net_ipv4_conf_all_arp_filter_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Comment out any occurrences + of net.ipv4.conf.all.arp_filter from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.arp_filter + replace: '#net.ipv4.conf.all.arp_filter' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Ensure sysctl net.ipv4.conf.all.arp_filter + is set + ansible.posix.sysctl: name: net.ipv4.conf.all.arp_filter value: '{{ sysctl_net_ipv4_conf_all_arp_filter_value }}' sysctl_file: /etc/sysctl.conf @@ -61779,6 +70684,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_arp_filter + + + + + @@ -61830,7 +70740,7 @@ sysctl_net_ipv4_conf_all_arp_ignore_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.arp_ignore is set - sysctl: +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Find all + files that contain net.ipv4.conf.all.arp_ignore + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_ignore\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Find all + files that set net.ipv4.conf.all.arp_ignore to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_ignore\s*=\s*{{ sysctl_net_ipv4_conf_all_arp_ignore_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Comment + out any occurrences of net.ipv4.conf.all.arp_ignore from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.arp_ignore + replace: '#net.ipv4.conf.all.arp_ignore' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Ensure sysctl + net.ipv4.conf.all.arp_ignore is set + ansible.posix.sysctl: name: net.ipv4.conf.all.arp_ignore value: '{{ sysctl_net_ipv4_conf_all_arp_ignore_value }}' sysctl_file: /etc/sysctl.conf @@ -61929,6 +70878,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_arp_ignore + + + + + @@ -61938,7 +70892,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces To set the runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.drop_gratuitous_arp=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.drop_gratuitous_arp = 1 @@ -61976,7 +70930,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.drop_gratuitous_arp # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.drop_gratuitous_arp="1" fi @@ -62020,16 +70974,12 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -62039,14 +70989,53 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp -- name: Comment out any occurrences of net.ipv4.conf.all.drop_gratuitous_arp from - config files - replace: - path: '{{ item.path }}' +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Find all files that contain + net.ipv4.conf.all.drop_gratuitous_arp + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.drop_gratuitous_arp\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Find all files that set + net.ipv4.conf.all.drop_gratuitous_arp to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.drop_gratuitous_arp\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Comment out any occurrences + of net.ipv4.conf.all.drop_gratuitous_arp from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp replace: '#net.ipv4.conf.all.drop_gratuitous_arp' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -62055,8 +71044,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp -- name: Ensure sysctl net.ipv4.conf.all.drop_gratuitous_arp is set to 1 - sysctl: +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Ensure sysctl net.ipv4.conf.all.drop_gratuitous_arp + is set to 1 + ansible.posix.sysctl: name: net.ipv4.conf.all.drop_gratuitous_arp value: '1' sysctl_file: /etc/sysctl.conf @@ -62071,6 +71061,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + + + + @@ -62088,11 +71082,10 @@ One such case is Libvirt; a toolkit By default, Libvirt requires IP forwarding to be enabled to facilitate network communication between the virtualization host and guest machines. It enables IP forwarding after every reboot. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-006028 - SV-271872r1092328_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006028 + SV-271872r1092328_rule IP forwarding permits the kernel to forward packets from one network interface to another. The ability to forward packets between two networks is only appropriate for systems acting as routers. @@ -62130,7 +71123,7 @@ sysctl_net_ipv4_conf_all_forwarding_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.forwarding is set - sysctl: +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Find + all files that contain net.ipv4.conf.all.forwarding + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.forwarding\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Find + all files that set net.ipv4.conf.all.forwarding to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.forwarding\s*=\s*{{ sysctl_net_ipv4_conf_all_forwarding_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Comment + out any occurrences of net.ipv4.conf.all.forwarding from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.forwarding + replace: '#net.ipv4.conf.all.forwarding' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Ensure + sysctl net.ipv4.conf.all.forwarding is set + ansible.posix.sysctl: name: net.ipv4.conf.all.forwarding value: '{{ sysctl_net_ipv4_conf_all_forwarding_value }}' sysctl_file: /etc/sysctl.conf @@ -62237,6 +71273,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_forwarding + + + + + @@ -62277,7 +71318,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -62357,10 +71397,10 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006022 - SV-271866r1092310_rule + OL09-00-006022 + SV-271866r1092310_rule The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity @@ -62398,7 +71438,7 @@ sysctl_net_ipv4_conf_all_log_martians_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.log_martians is set - sysctl: +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Find + all files that contain net.ipv4.conf.all.log_martians + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.log_martians\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Find + all files that set net.ipv4.conf.all.log_martians to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.log_martians\s*=\s*{{ sysctl_net_ipv4_conf_all_log_martians_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Comment + out any occurrences of net.ipv4.conf.all.log_martians from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.log_martians + replace: '#net.ipv4.conf.all.log_martians' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Ensure + sysctl net.ipv4.conf.all.log_martians is set + ansible.posix.sysctl: name: net.ipv4.conf.all.log_martians value: '{{ sysctl_net_ipv4_conf_all_log_martians_value }}' sysctl_file: /etc/sysctl.conf @@ -62518,6 +71606,11 @@ fi - sysctl_net_ipv4_conf_all_log_martians - unknown_severity + + + + + @@ -62566,7 +71659,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.route_localnet # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.route_localnet="0" fi @@ -62610,16 +71703,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.route_localnet.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -62629,14 +71719,54 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet -- name: Comment out any occurrences of net.ipv4.conf.all.route_localnet from config +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.route_localnet + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.route_localnet\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.route_localnet to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.route_localnet\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.route_localnet from config files - replace: - path: '{{ item.path }}' + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.route_localnet replace: '#net.ipv4.conf.all.route_localnet' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -62645,8 +71775,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet -- name: Ensure sysctl net.ipv4.conf.all.route_localnet is set to 0 - sysctl: +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.route_localnet is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.all.route_localnet value: '0' sysctl_file: /etc/sysctl.conf @@ -62661,6 +71792,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet + + + + @@ -62698,7 +71833,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -62755,13 +71889,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-5 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 1.4 - OL09-00-006024 - SV-271868r1092316_rule + OL09-00-006024 + SV-271868r1092316_rule Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for @@ -62800,7 +71934,7 @@ sysctl_net_ipv4_conf_all_rp_filter_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.rp_filter is set - sysctl: +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.rp_filter + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.rp_filter\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.rp_filter to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.rp_filter\s*=\s*{{ sysctl_net_ipv4_conf_all_rp_filter_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.rp_filter from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.rp_filter + replace: '#net.ipv4.conf.all.rp_filter' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.rp_filter is set + ansible.posix.sysctl: name: net.ipv4.conf.all.rp_filter value: '{{ sysctl_net_ipv4_conf_all_rp_filter_value }}' sysctl_file: /etc/sysctl.conf @@ -62935,7 +72126,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_rp_filter + + + + + + @@ -62980,8 +72177,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-001503 - CCI-001551 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -63088,7 +72283,7 @@ To make sure that the setting is persistent, add the following line to a file in PR.PT-3 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 @@ -63129,7 +72324,7 @@ sysctl_net_ipv4_conf_all_secure_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.secure_redirects is set - sysctl: +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.secure_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.secure_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.secure_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.secure_redirects\s*=\s*{{ sysctl_net_ipv4_conf_all_secure_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.secure_redirects from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.secure_redirects + replace: '#net.ipv4.conf.all.secure_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.secure_redirects is set + ansible.posix.sysctl: name: net.ipv4.conf.all.secure_redirects value: '{{ sysctl_net_ipv4_conf_all_secure_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -63261,6 +72511,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_secure_redirects + + + + + @@ -63312,7 +72567,7 @@ sysctl_net_ipv4_conf_all_shared_media_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.shared_media is set - sysctl: +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.shared_media + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.shared_media\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.shared_media to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.shared_media\s*=\s*{{ sysctl_net_ipv4_conf_all_shared_media_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.shared_media from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.shared_media + replace: '#net.ipv4.conf.all.shared_media' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.shared_media is set + ansible.posix.sysctl: name: net.ipv4.conf.all.shared_media value: '{{ sysctl_net_ipv4_conf_all_shared_media_value }}' sysctl_file: /etc/sysctl.conf @@ -63412,6 +72705,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_shared_media + + + + + @@ -63459,7 +72757,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -63566,13 +72863,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.PT-3 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 1.4 - OL09-00-006025 - SV-271869r1092319_rule + OL09-00-006025 + SV-271869r1092319_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect @@ -63612,7 +72909,7 @@ sysctl_net_ipv4_conf_default_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.accept_redirects is set - sysctl: +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Find all files that contain net.ipv4.conf.default.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Find all files that set net.ipv4.conf.default.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_redirects\s*=\s*{{ sysctl_net_ipv4_conf_default_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.default.accept_redirects from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.accept_redirects + replace: '#net.ipv4.conf.default.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.default.accept_redirects is set + ansible.posix.sysctl: name: net.ipv4.conf.default.accept_redirects value: '{{ sysctl_net_ipv4_conf_default_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -63752,6 +73108,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_accept_redirects + + + + + @@ -63799,7 +73160,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -63892,10 +73252,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -63909,11 +73269,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006026 - SV-271870r1092322_rule + OL09-00-006026 + SV-271870r1092322_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. @@ -63955,7 +73315,7 @@ sysctl_net_ipv4_conf_default_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Find all files that contain net.ipv4.conf.default.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Find all files that set net.ipv4.conf.default.accept_source_route + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_source_route\s*=\s*{{ sysctl_net_ipv4_conf_default_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Comment out any occurrences of net.ipv4.conf.default.accept_source_route + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.accept_source_route + replace: '#net.ipv4.conf.default.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Ensure sysctl net.ipv4.conf.default.accept_source_route is set + ansible.posix.sysctl: name: net.ipv4.conf.default.accept_source_route value: '{{ sysctl_net_ipv4_conf_default_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -64083,6 +73497,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_accept_source_route + + + + + @@ -64092,7 +73511,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default To set the runtime status of the net.ipv4.conf.default.log_martians kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.log_martians=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.log_martians = 1 @@ -64123,7 +73542,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -64203,10 +73621,10 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006023 - SV-271867r1092313_rule + OL09-00-006023 + SV-271867r1092313_rule The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity @@ -64244,7 +73662,7 @@ sysctl_net_ipv4_conf_default_log_martians_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.log_martians is set - sysctl: +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Find all files that contain net.ipv4.conf.default.log_martians + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.log_martians\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Find all files that set net.ipv4.conf.default.log_martians to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.log_martians\s*=\s*{{ sysctl_net_ipv4_conf_default_log_martians_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Comment out any occurrences of net.ipv4.conf.default.log_martians from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.log_martians + replace: '#net.ipv4.conf.default.log_martians' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Ensure sysctl net.ipv4.conf.default.log_martians is set + ansible.posix.sysctl: name: net.ipv4.conf.default.log_martians value: '{{ sysctl_net_ipv4_conf_default_log_martians_value }}' sysctl_file: /etc/sysctl.conf @@ -64364,6 +73831,11 @@ fi - sysctl_net_ipv4_conf_default_log_martians - unknown_severity + + + + + @@ -64402,7 +73874,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -64458,11 +73929,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-4 PR.DS-5 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006027 - SV-271871r1092325_rule + OL09-00-006027 + SV-271871r1092325_rule Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for @@ -64501,7 +73972,7 @@ sysctl_net_ipv4_conf_default_rp_filter_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.rp_filter is set - sysctl: +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Find all files that contain net.ipv4.conf.default.rp_filter + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.rp_filter\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Find all files that set net.ipv4.conf.default.rp_filter to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.rp_filter\s*=\s*{{ sysctl_net_ipv4_conf_default_rp_filter_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Comment out any occurrences of net.ipv4.conf.default.rp_filter from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.rp_filter + replace: '#net.ipv4.conf.default.rp_filter' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Ensure sysctl net.ipv4.conf.default.rp_filter is set + ansible.posix.sysctl: name: net.ipv4.conf.default.rp_filter value: '{{ sysctl_net_ipv4_conf_default_rp_filter_value }}' sysctl_file: /etc/sysctl.conf @@ -64625,6 +74148,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_rp_filter + + + + + @@ -64671,7 +74199,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-001551 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -64764,10 +74291,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -64781,7 +74308,7 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 Accepting "secure" ICMP redirects (from those gateways listed as @@ -64820,7 +74347,7 @@ sysctl_net_ipv4_conf_default_secure_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.secure_redirects is set - sysctl: +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Find + all files that contain net.ipv4.conf.default.secure_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.secure_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Find + all files that set net.ipv4.conf.default.secure_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.secure_redirects\s*=\s*{{ sysctl_net_ipv4_conf_default_secure_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Comment + out any occurrences of net.ipv4.conf.default.secure_redirects from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.secure_redirects + replace: '#net.ipv4.conf.default.secure_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Ensure + sysctl net.ipv4.conf.default.secure_redirects is set + ansible.posix.sysctl: name: net.ipv4.conf.default.secure_redirects value: '{{ sysctl_net_ipv4_conf_default_secure_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -64940,6 +74515,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_secure_redirects + + + + + @@ -64991,7 +74571,7 @@ sysctl_net_ipv4_conf_default_shared_media_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.shared_media is set - sysctl: +- name: Configure Sending and Accepting Shared Media Redirects by Default - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Find all + files that contain net.ipv4.conf.default.shared_media + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.shared_media\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Find all + files that set net.ipv4.conf.default.shared_media to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.shared_media\s*=\s*{{ sysctl_net_ipv4_conf_default_shared_media_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Comment + out any occurrences of net.ipv4.conf.default.shared_media from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.shared_media + replace: '#net.ipv4.conf.default.shared_media' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Ensure + sysctl net.ipv4.conf.default.shared_media is set + ansible.posix.sysctl: name: net.ipv4.conf.default.shared_media value: '{{ sysctl_net_ipv4_conf_default_shared_media_value }}' sysctl_file: /etc/sysctl.conf @@ -65091,6 +74709,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_shared_media + + + + + @@ -65138,7 +74761,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -65231,10 +74853,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -65248,12 +74870,12 @@ To make sure that the setting is persistent, add the following line to a file in PR.PT-3 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 1.4.2 1.4 - OL09-00-006030 - SV-271873r1092331_rule + OL09-00-006030 + SV-271873r1092331_rule Responding to broadcast (ICMP) echoes facilitates network mapping and provides a vector for amplification attacks. @@ -65292,7 +74914,7 @@ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value=' tags: - always -- name: Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set - sysctl: +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Find all files that contain net.ipv4.icmp_echo_ignore_broadcasts + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_echo_ignore_broadcasts\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Find all files that set net.ipv4.icmp_echo_ignore_broadcasts to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_echo_ignore_broadcasts\s*=\s*{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts + replace: '#net.ipv4.icmp_echo_ignore_broadcasts' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set + ansible.posix.sysctl: name: net.ipv4.icmp_echo_ignore_broadcasts value: '{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value }}' sysctl_file: /etc/sysctl.conf @@ -65428,6 +75107,11 @@ fi - reboot_required - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + + + + + @@ -65466,7 +75150,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -65523,10 +75206,10 @@ To make sure that the setting is persistent, add the following line to a file in A.14.2.4 A.17.2.1 A.9.1.2 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -65535,13 +75218,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.2 1.4 - OL09-00-006031 - SV-271874r1092612_rule + OL09-00-006031 + SV-271874r1092612_rule Ignoring bogus ICMP error responses reduces log size, although some activity would not be logged. # Remediation is applicable only in certain platforms @@ -65577,7 +75260,7 @@ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value=' tags: - always -- name: Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set - sysctl: +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Find all files that contain net.ipv4.icmp_ignore_bogus_error_responses + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_ignore_bogus_error_responses\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Find all files that set net.ipv4.icmp_ignore_bogus_error_responses to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_ignore_bogus_error_responses\s*=\s*{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses + replace: '#net.ipv4.icmp_ignore_bogus_error_responses' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set + ansible.posix.sysctl: name: net.ipv4.icmp_ignore_bogus_error_responses value: '{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value }}' sysctl_file: /etc/sysctl.conf @@ -65709,6 +75448,11 @@ fi - sysctl_net_ipv4_icmp_ignore_bogus_error_responses - unknown_severity + + + + + @@ -65757,7 +75501,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.ip_local_port_range # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.ip_local_port_range="32768 65535" fi @@ -65801,16 +75545,12 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Set Kernel Parameter to Increase Local Port Range - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.ip_local_port_range.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -65820,13 +75560,53 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range -- name: Comment out any occurrences of net.ipv4.ip_local_port_range from config files - replace: - path: '{{ item.path }}' +- name: Set Kernel Parameter to Increase Local Port Range - Find all files that contain + net.ipv4.ip_local_port_range + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_local_port_range\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: Set Kernel Parameter to Increase Local Port Range - Find all files that set + net.ipv4.ip_local_port_range to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_local_port_range\s*=\s*32768 65535$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: Set Kernel Parameter to Increase Local Port Range - Comment out any occurrences + of net.ipv4.ip_local_port_range from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.ip_local_port_range replace: '#net.ipv4.ip_local_port_range' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -65835,8 +75615,9 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range -- name: Ensure sysctl net.ipv4.ip_local_port_range is set to 32768 65535 - sysctl: +- name: Set Kernel Parameter to Increase Local Port Range - Ensure sysctl net.ipv4.ip_local_port_range + is set to 32768 65535 + ansible.posix.sysctl: name: net.ipv4.ip_local_port_range value: 32768 65535 sysctl_file: /etc/sysctl.conf @@ -65851,6 +75632,10 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range + + + + @@ -65900,7 +75685,7 @@ sysctl_net_ipv4_tcp_rfc1337_value=' tags: - always -- name: Ensure sysctl net.ipv4.tcp_rfc1337 is set - sysctl: +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Find all + files that contain net.ipv4.tcp_rfc1337 + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_rfc1337\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Find all + files that set net.ipv4.tcp_rfc1337 to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_rfc1337\s*=\s*{{ sysctl_net_ipv4_tcp_rfc1337_value }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Comment out + any occurrences of net.ipv4.tcp_rfc1337 from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.tcp_rfc1337 + replace: '#net.ipv4.tcp_rfc1337' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Ensure sysctl + net.ipv4.tcp_rfc1337 is set + ansible.posix.sysctl: name: net.ipv4.tcp_rfc1337 value: '{{ sysctl_net_ipv4_tcp_rfc1337_value }}' sysctl_file: /etc/sysctl.conf @@ -65999,6 +75822,11 @@ fi - reboot_required - sysctl_net_ipv4_tcp_rfc1337 + + + + + @@ -66038,9 +75866,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-001095 - CCI-000366 - CCI-002385 4.2.3.4 4.3.3.4 4.4.3.3 @@ -66099,15 +75924,15 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-5 PR.PT-4 Req-1.4.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000420-GPOS-00186 - SRG-OS-000142-GPOS-00071 + SRG-OS-000480-GPOS-00227 + SRG-OS-000420-GPOS-00186 + SRG-OS-000142-GPOS-00071 R12 A.8.SEC-OL6 1.4.3 1.4 - OL09-00-006050 - SV-271884r1092364_rule + OL09-00-006050 + SV-271884r1092364_rule A TCP SYN flood attack can cause a denial of service by filling a system's TCP connection table with connections in the SYN_RCVD state. Syncookies can be used to track a connection when a subsequent ACK is received, @@ -66147,7 +75972,7 @@ sysctl_net_ipv4_tcp_syncookies_value=' tags: - always -- name: Ensure sysctl net.ipv4.tcp_syncookies is set - sysctl: +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Find + all files that contain net.ipv4.tcp_syncookies + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_syncookies\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Find + all files that set net.ipv4.tcp_syncookies to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_syncookies\s*=\s*{{ sysctl_net_ipv4_tcp_syncookies_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Comment + out any occurrences of net.ipv4.tcp_syncookies from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.tcp_syncookies + replace: '#net.ipv4.tcp_syncookies' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Ensure + sysctl net.ipv4.tcp_syncookies is set + ansible.posix.sysctl: name: net.ipv4.tcp_syncookies value: '{{ sysctl_net_ipv4_tcp_syncookies_value }}' sysctl_file: /etc/sysctl.conf @@ -66294,6 +76182,11 @@ fi - reboot_required - sysctl_net_ipv4_tcp_syncookies + + + + + @@ -66348,7 +76241,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -66441,10 +76333,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -66459,13 +76351,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.5 1.4 - OL09-00-006032 - SV-271875r1092337_rule + OL09-00-006032 + SV-271875r1092337_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology. @@ -66502,7 +76394,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.send_redirects # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.send_redirects="0" fi @@ -66556,16 +76448,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.send_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.1 @@ -66585,14 +76474,74 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects -- name: Comment out any occurrences of net.ipv4.conf.all.send_redirects from config +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.send_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.send_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.send_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.send_redirects\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.send_redirects from config files - replace: - path: '{{ item.path }}' + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.send_redirects replace: '#net.ipv4.conf.all.send_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - CJIS-5.10.1.1 - DISA-STIG-OL09-00-006032 @@ -66611,8 +76560,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects -- name: Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0 - sysctl: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.all.send_redirects value: '0' sysctl_file: /etc/sysctl.conf @@ -66637,6 +76587,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects + + + + @@ -66683,7 +76637,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -66776,10 +76729,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -66794,13 +76747,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.5 1.4 - OL09-00-006033 - SV-271876r1092641_rule + OL09-00-006033 + SV-271876r1092641_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology. @@ -66837,7 +76790,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.default.send_redirects # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.default.send_redirects="0" fi @@ -66891,16 +76844,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.send_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.1 @@ -66920,14 +76870,75 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects -- name: Comment out any occurrences of net.ipv4.conf.default.send_redirects from config - files - replace: - path: '{{ item.path }}' +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Find all files that contain net.ipv4.conf.default.send_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.send_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Find all files that set net.ipv4.conf.default.send_redirects to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.send_redirects\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Comment out any occurrences of net.ipv4.conf.default.send_redirects + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.default.send_redirects replace: '#net.ipv4.conf.default.send_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - CJIS-5.10.1.1 - DISA-STIG-OL09-00-006033 @@ -66946,8 +76957,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects -- name: Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0 - sysctl: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.default.send_redirects value: '0' sysctl_file: /etc/sysctl.conf @@ -66972,6 +76984,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects + + + + @@ -67012,7 +77028,6 @@ profiles or benchmarks that target usage of IPv4 forwarding. DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -67080,10 +77095,10 @@ profiles or benchmarks that target usage of IPv4 forwarding. A.14.2.4 A.17.2.1 A.9.1.2 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -67096,7 +77111,7 @@ profiles or benchmarks that target usage of IPv4 forwarding. PR.PT-4 Req-1.3.1 Req-1.3.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 @@ -67136,7 +77151,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.ip_forward # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.ip_forward="0" fi @@ -67190,16 +77205,13 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Set fact for + sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.ip_forward.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.20 @@ -67219,13 +77231,73 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward -- name: Comment out any occurrences of net.ipv4.ip_forward from config files - replace: - path: '{{ item.path }}' +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Find all files + that contain net.ipv4.ip_forward + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_forward\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Find all files + that set net.ipv4.ip_forward to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_forward\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Comment out + any occurrences of net.ipv4.ip_forward from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.ip_forward replace: '#net.ipv4.ip_forward' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-171-3.1.20 - NIST-800-53-CM-6(a) @@ -67244,8 +77316,9 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward -- name: Ensure sysctl net.ipv4.ip_forward is set to 0 - sysctl: +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Ensure sysctl + net.ipv4.ip_forward is set to 0 + ansible.posix.sysctl: name: net.ipv4.ip_forward value: '0' sysctl_file: /etc/sysctl.conf @@ -67270,6 +77343,10 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward + + + + @@ -67312,7 +77389,7 @@ originating from within a corporate network to include malicious mobile code and configured software on a host. # Remediation is applicable only in certain platforms -if ( rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then +if ( ! (systemctl is-active iptables &>/dev/null) && ! (systemctl is-active ufw &>/dev/null) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if ! rpm -q --quiet "nftables" ; then yum install -y "nftables" @@ -67336,7 +77413,7 @@ fi - package_nftables_installed - name: Ensure nftables is installed - package: + ansible.builtin.package: name: nftables state: present when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -67425,86 +77502,52 @@ fi - no_reboot_needed - service_nftables_disabled -- name: Verify nftables Service is Disabled - Collect systemd Services Present in - the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Verify nftables Service is Disabled - Disable service nftables + block: + + - name: Verify nftables Service is Disabled - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Verify nftables Service is Disabled - Ensure nftables.service is Masked + ansible.builtin.systemd: + name: nftables.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("nftables.service", multiline=True) + + - name: Unit Socket Exists - nftables.socket + ansible.builtin.command: systemctl -q list-unit-files nftables.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Verify nftables Service is Disabled - Disable Socket nftables + ansible.builtin.systemd: + name: nftables.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("nftables.socket", multiline=True) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + - special_service_block when: ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled - -- name: Verify nftables Service is Disabled - Ensure nftables.service is Masked - ansible.builtin.systemd: - name: nftables.service - state: stopped - enabled: false - masked: true - when: - - ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages - and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ) - - service_exists.stdout_lines is search("nftables.service", multiline=True) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled - -- name: Unit Socket Exists - nftables.socket - ansible.builtin.command: systemctl -q list-unit-files nftables.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages - and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled - -- name: Verify nftables Service is Disabled - Disable Socket nftables - ansible.builtin.systemd: - name: nftables.socket - enabled: false - state: stopped - masked: true - when: - - ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages - and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ) - - socket_file_exists.stdout_lines is search("nftables.socket", multiline=True) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled include disable_nftables @@ -67519,6 +77562,10 @@ class disable_nftables { [customizations.services] masked = ["nftables"] + + + + @@ -67528,7 +77575,8 @@ masked = ["nftables"] Verify Group Who Owns /etc/nftables Directory - To properly set the group owner of /etc/nftables, run the command: $ sudo chgrp root /etc/nftables + To properly set the group owner of /etc/nftables, run the command: +$ sudo chgrp root /etc/nftables R50 The ownership of the /etc/nftables directory by the root group is important @@ -67539,7 +77587,17 @@ ensures exclusive control of the nftables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q nftables; then -find -H /etc/nftables/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/nftables/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -67556,11 +77614,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"nftables" in ansible_facts.packages' + - directory_groupowner_etc_nftables_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_nftables_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_nftables_newgroup: root + when: + - '"nftables" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/nftables/ - file: + ansible.builtin.file: path: /etc/nftables/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_nftables_newgroup }}' when: '"nftables" in ansible_facts.packages' tags: - configure_strategy @@ -67579,7 +77668,8 @@ fi Verify User Who Owns /etc/nftables Directory - To properly set the owner of /etc/nftables, run the command: $ sudo chown root /etc/nftables + To properly set the owner of /etc/nftables, run the command: +$ sudo chown root /etc/nftables R50 The ownership of the /etc/nftables directory by the root user is important @@ -67590,7 +77680,17 @@ ensures exclusive control of the nftables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q nftables; then -find -H /etc/nftables/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/nftables/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -67607,11 +77707,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_nftables_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_nftables_newown: '0' + when: '"nftables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/nftables/ - file: + ansible.builtin.file: path: /etc/nftables/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_nftables_newown }}' when: '"nftables" in ansible_facts.packages' tags: - configure_strategy @@ -67641,7 +77754,7 @@ ensures exclusive control of the nftables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q nftables; then -find -H /etc/nftables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/nftables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -67659,7 +77772,8 @@ fi - no_reboot_needed - name: Find /etc/nftables/ file(s) - command: 'find -H /etc/nftables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/nftables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -67674,7 +77788,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/nftables/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -67725,8 +77839,7 @@ for other distributions and graphical frontends. The ufw service can be enabled with the following command: $ sudo systemctl enable ufw.service - CCI-002314 - SRG-OS-000297-GPOS-00115 + SRG-OS-000297-GPOS-00115 The ufw service must be enabled and running in order for ufw to protect the system # Remediation is applicable only in certain platforms @@ -67758,7 +77871,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Verify ufw Enabled - Enable Service ufw @@ -67769,10 +77882,6 @@ fi masked: false when: - '"ufw" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ( "ufw" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" - in ansible_facts.packages) ) tags: - enable_strategy - low_complexity @@ -67780,6 +77889,11 @@ fi - medium_severity - no_reboot_needed - service_ufw_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "ufw" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) include enable_ufw @@ -67794,6 +77908,10 @@ class enable_ufw { [customizations.services] enabled = ["ufw"] + + + + @@ -67821,17 +77939,21 @@ and virtual paths. To configure the system to prevent the atm kernel module from being loaded, add the following line to the file /etc/modprobe.d/atm.conf: install atm /bin/false +This entry will cause a non-zero return value during a atm module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install atm /bin/true To configure the system to prevent the atm from being used, add the following line to file /etc/modprobe.d/atm.conf: blacklist atm - CCI-000381 AC-18 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000040 - SV-271443r1092463_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000040 + SV-271443r1092463_rule Disabling ATM protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -67867,7 +77989,7 @@ fi - reboot_required - name: Ensure kernel module 'atm' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/atm.conf regexp: install\s+atm @@ -67884,7 +78006,7 @@ fi - reboot_required - name: Ensure kernel module 'atm' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/atm.conf regexp: ^blacklist atm$ @@ -67916,18 +78038,22 @@ is now also used in marine, industrial, and medical applications. To configure the system to prevent the can kernel module from being loaded, add the following line to the file /etc/modprobe.d/can.conf: install can /bin/false +This entry will cause a non-zero return value during a can module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install can /bin/true To configure the system to prevent the can from being used, add the following line to file /etc/modprobe.d/can.conf: blacklist can - CCI-000381 AC-18 FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000041 - SV-271444r1091044_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000041 + SV-271444r1091044_rule Disabling CAN protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -67963,7 +78089,7 @@ fi - reboot_required - name: Ensure kernel module 'can' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/can.conf regexp: install\s+can @@ -67980,7 +78106,7 @@ fi - reboot_required - name: Ensure kernel module 'can' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/can.conf regexp: ^blacklist can$ @@ -68012,6 +78138,11 @@ streaming media and telephony. To configure the system to prevent the dccp kernel module from being loaded, add the following line to the file /etc/modprobe.d/dccp.conf: install dccp /bin/false +This entry will cause a non-zero return value during a dccp module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install dccp /bin/true To configure the system to prevent the dccp from being used, add the following line to file /etc/modprobe.d/dccp.conf: @@ -68030,7 +78161,6 @@ add the following line to file /etc/modprobe.d/dccp.conf: DSS05.05 DSS06.06 3.4.6 - CCI-001958 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68088,8 +78218,8 @@ add the following line to file /etc/modprobe.d/dccp.conf: PR.IP-1 PR.PT-3 Req-1.4.2 - SRG-OS-000096-GPOS-00050 - SRG-OS-000378-GPOS-00163 + SRG-OS-000096-GPOS-00050 + SRG-OS-000378-GPOS-00163 1.4.2 1.4 Disabling DCCP protects @@ -68133,7 +78263,7 @@ fi - reboot_required - name: Ensure kernel module 'dccp' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/dccp.conf regexp: install\s+dccp @@ -68156,7 +78286,7 @@ fi - reboot_required - name: Ensure kernel module 'dccp' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/dccp.conf regexp: ^blacklist dccp$ @@ -68193,16 +78323,20 @@ high-speed real-time communication. To configure the system to prevent the firewire-core kernel module from being loaded, add the following line to the file /etc/modprobe.d/firewire-core.conf: install firewire-core /bin/false +This entry will cause a non-zero return value during a firewire-core module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install firewire-core /bin/true To configure the system to prevent the firewire-core from being used, add the following line to file /etc/modprobe.d/firewire-core.conf: blacklist firewire-core - CCI-000381 AC-18 - SRG-OS-000095-GPOS-00049 - OL09-00-000042 - SV-271445r1091047_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000042 + SV-271445r1091047_rule Disabling FireWire protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -68238,7 +78372,7 @@ fi - reboot_required - name: Ensure kernel module 'firewire-core' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/firewire-core.conf regexp: install\s+firewire-core @@ -68255,7 +78389,7 @@ fi - reboot_required - name: Ensure kernel module 'firewire-core' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/firewire-core.conf regexp: ^blacklist firewire-core$ @@ -68287,6 +78421,11 @@ low-latency communications between nodes in a cluster. To configure the system to prevent the rds kernel module from being loaded, add the following line to the file /etc/modprobe.d/rds.conf: install rds /bin/false +This entry will cause a non-zero return value during a rds module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install rds /bin/true To configure the system to prevent the rds from being used, add the following line to file /etc/modprobe.d/rds.conf: @@ -68395,7 +78534,7 @@ fi - reboot_required - name: Ensure kernel module 'rds' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/rds.conf regexp: install\s+rds @@ -68413,7 +78552,7 @@ fi - reboot_required - name: Ensure kernel module 'rds' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/rds.conf regexp: ^blacklist rds$ @@ -68447,6 +78586,11 @@ within one connection. To configure the system to prevent the sctp kernel module from being loaded, add the following line to the file /etc/modprobe.d/sctp.conf: install sctp /bin/false +This entry will cause a non-zero return value during a sctp module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install sctp /bin/true To configure the system to prevent the sctp from being used, add the following line to file /etc/modprobe.d/sctp.conf: @@ -68465,7 +78609,6 @@ add the following line to file /etc/modprobe.d/sctp.conf: DSS05.05 DSS06.06 3.4.6 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68524,12 +78667,12 @@ add the following line to file /etc/modprobe.d/sctp.conf: PR.PT-3 FMT_SMF_EXT.1 Req-1.4.2 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 1.4.2 1.4 - OL09-00-000043 - SV-271446r1091050_rule + OL09-00-000043 + SV-271446r1091050_rule Disabling SCTP protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -68572,7 +78715,7 @@ fi - reboot_required - name: Ensure kernel module 'sctp' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/sctp.conf regexp: install\s+sctp @@ -68596,7 +78739,7 @@ fi - reboot_required - name: Ensure kernel module 'sctp' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/sctp.conf regexp: ^blacklist sctp$ @@ -68635,6 +78778,11 @@ cluster. To configure the system to prevent the tipc kernel module from being loaded, add the following line to the file /etc/modprobe.d/tipc.conf: install tipc /bin/false +This entry will cause a non-zero return value during a tipc module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install tipc /bin/true To configure the system to prevent the tipc from being used, add the following line to file /etc/modprobe.d/tipc.conf: @@ -68655,7 +78803,6 @@ the tipc kernel module will be loaded.DSS05.02 DSS05.05 DSS06.06 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68713,9 +78860,9 @@ the tipc kernel module will be loaded.PR.IP-1 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - OL09-00-000044 - SV-271447r1092464_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000044 + SV-271447r1092464_rule Disabling TIPC protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -68753,7 +78900,7 @@ fi - reboot_required - name: Ensure kernel module 'tipc' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/tipc.conf regexp: install\s+tipc @@ -68772,7 +78919,7 @@ fi - reboot_required - name: Ensure kernel module 'tipc' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/tipc.conf regexp: ^blacklist tipc$ @@ -68849,8 +78996,6 @@ to prevent the loading of the Bluetooth module: DSS05.05 DSS06.06 3.1.16 - CCI-001443 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68928,10 +79073,10 @@ to prevent the loading of the Bluetooth module: PR.PT-3 PR.PT-4 FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - SRG-OS-000300-GPOS-00118 - OL09-00-000046 - SV-271449r1091059_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000300-GPOS-00118 + OL09-00-000046 + SV-271449r1091059_rule If Bluetooth functionality must be disabled, preventing the kernel from loading the kernel module provides an additional safeguard against its activation. @@ -68976,7 +79121,7 @@ fi - reboot_required - name: Ensure kernel module 'bluetooth' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/bluetooth.conf regexp: install\s+bluetooth @@ -69000,7 +79145,7 @@ fi - reboot_required - name: Ensure kernel module 'bluetooth' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/bluetooth.conf regexp: ^blacklist bluetooth$ @@ -69058,10 +79203,6 @@ Configure the system to disable all wireless network interfaces with the followi DSS05.05 DSS06.06 3.1.16 - CCI-001443 - CCI-001444 - CCI-002421 - CCI-002418 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -69115,8 +79256,6 @@ Configure the system to disable all wireless network interfaces with the followi SR 5.3 SR 7.1 SR 7.6 - 1315 - 1319 A.11.2.6 A.12.1.2 A.12.5.1 @@ -69141,14 +79280,16 @@ Configure the system to disable all wireless network interfaces with the followi PR.PT-3 PR.PT-4 Req-1.3.3 - SRG-OS-000299-GPOS-00117 - SRG-OS-000300-GPOS-00118 - SRG-OS-000424-GPOS-00188 - SRG-OS-000481-GPOS-000481 + SRG-OS-000299-GPOS-00117 + SRG-OS-000300-GPOS-00118 + SRG-OS-000424-GPOS-00188 + SRG-OS-000481-GPOS-00481 + 1315 + 1319 1.3.3 1.3 - OL09-00-006001 - SV-271859r1092289_rule + OL09-00-006001 + SV-271859r1092289_rule The use of wireless networking can introduce many different attack vectors into the organization's network. Common attack vectors such as malicious association and ad hoc networks will allow an attacker to spoof a wireless access point @@ -69156,8 +79297,10 @@ and ad hoc networks will allow an attacker to spoof a wireless access point attacker to monitor and record network traffic. These malicious APs can also serve to create a man-in-the-middle attack or be used to create a denial of service to valid network resources. - - + + # Remediation is applicable only in certain platforms +if ( ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + if ! rpm -q --quiet "NetworkManager" ; then yum install -y "NetworkManager" fi @@ -69175,6 +79318,10 @@ if command -v wicked >/dev/null 2>&1 && systemctl is-active wi done fi fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - name: Gather the package facts package_facts: @@ -69200,6 +79347,8 @@ fi - name: Service facts ansible.builtin.service_facts: null + when: ( not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) tags: - DISA-STIG-OL09-00-006001 - NIST-800-171-3.1.16 @@ -69225,6 +79374,8 @@ fi state: present with_items: - NetworkManager + when: ( not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) tags: - DISA-STIG-OL09-00-006001 - NIST-800-171-3.1.16 @@ -69245,8 +79396,10 @@ fi - wireless_disable_interfaces - name: NetworkManager Deactivate Wireless Network Interfaces - command: nmcli radio wifi off + ansible.builtin.command: nmcli radio wifi off when: + - ( not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) ) - '''NetworkManager'' in ansible_facts.packages' - ansible_facts.services['NetworkManager.service'].state == 'running' tags: @@ -69277,6 +79430,37 @@ fi + + Transport Layer Security Support + Support for Transport Layer Security (TLS), and its predecessor, the Secure +Sockets Layer (SSL), is included in Red Hat Enterprise Linux in the OpenSSL software (RPM package +openssl). TLS provides encrypted and authenticated network +communications, and many network services include support for it. TLS or SSL +can be leveraged to avoid any plaintext transmission of sensitive data. + +For information on how to use OpenSSL, see +http://www.openssl.org/docs/. Information on FIPS validation +of OpenSSL is available at http://www.openssl.org/docs/fips.html +and http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140val-all.htm. + + Only Allow DoD PKI-established CAs + The operating system must only allow the use of DoD PKI-established +certificate authorities for verification of the establishment of +protected sessions. + SRG-OS-000403-GPOS-00182 + OL09-00-900140 + SV-271901r1092415_rule + Untrusted Certificate Authorities (CA) can issue certificates, but they +may be issued by organizations or individuals that seek to compromise +DoD systems or by organizations with insufficient security controls. If +the CA used for verifying the certificate is not a DoD-approved CA, +trust of this CA has not been established. +The DoD will only accept PKI-certificates obtained from a DoD-approved +internal or external certificate authority. Reliance on CAs for the +establishment of secure sessions includes, for example, the use of +SSL/TLS certificates. + + Network Manager The NetworkManager daemon configures a variety of network connections. @@ -69294,96 +79478,163 @@ default - NetworkManager will update /etc/resolv.conf to reflect the nameservers NetworkManager DNS Mode Must Be Must Configured The DNS processing mode in NetworkManager describes how DNS is processed on the system. Depending the mode some changes the system's DNS may not be respected. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-006002 - SV-271860r1092292_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006002 + SV-271860r1092292_rule To ensure that DNS resolver settings are respected, a DNS mode in NetworkManager must be configured. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q NetworkManager; then var_networkmanager_dns_mode='' +found=false - -# Try find '[main]' and 'dns' in '/etc/NetworkManager/NetworkManager.conf', if it exists, set -# to '$var_networkmanager_dns_mode', if it isn't here, add it, if '[main]' doesn't exist, add it there -if grep -qzosP '[[:space:]]*\[main]([^\n\[]*\n+)+?[[:space:]]*dns' '/etc/NetworkManager/NetworkManager.conf'; then - - sed -i "s/dns[^(\n)]*/dns=$var_networkmanager_dns_mode/" '/etc/NetworkManager/NetworkManager.conf' -elif grep -qs '[[:space:]]*\[main]' '/etc/NetworkManager/NetworkManager.conf'; then - sed -i "/[[:space:]]*\[main]/a dns=$var_networkmanager_dns_mode" '/etc/NetworkManager/NetworkManager.conf' -else - if test -d "/etc/NetworkManager"; then - printf '%s\n' '[main]' "dns=$var_networkmanager_dns_mode" >> '/etc/NetworkManager/NetworkManager.conf' - else - echo "Config file directory '/etc/NetworkManager' doesnt exist, not remediating, assuming non-applicability." >&2 +# set value in all files if they contain section or key +for f in $(echo -n "/etc/NetworkManager/conf.d/complianceascode_hardening.conf /etc/NetworkManager/conf.d/*.conf /etc/NetworkManager/NetworkManager.conf"); do + if [ ! -e "$f" ]; then + continue fi -fi -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then - systemctl reload NetworkManager + # find key in section and change value + if grep -qzosP "[[:space:]]*\[main\]([^\n\[]*\n+)+?[[:space:]]*dns" "$f"; then + if ! grep -qPz "dns=$var_networkmanager_dns_mode" "$f"; then + + sed -i "s/dns[^(\n)]*/dns=$var_networkmanager_dns_mode/" "$f" + + fi + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[main\]" "$f"; then + + sed -i "/[[:space:]]*\[main\]/a dns=$var_networkmanager_dns_mode" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/NetworkManager/conf.d/complianceascode_hardening.conf /etc/NetworkManager/conf.d/*.conf /etc/NetworkManager/NetworkManager.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[main]\ndns=$var_networkmanager_dns_mode" >> "$file" + fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: - DISA-STIG-OL09-00-006002 - NIST-800-53-CM-6(b) - - configure_strategy - low_complexity - low_disruption - medium_severity - networkmanager_dns_mode - no_reboot_needed + - restrict_strategy - name: XCCDF Value var_networkmanager_dns_mode # promote to variable set_fact: var_networkmanager_dns_mode: !!str tags: - always -- name: Set 'dns' to '{{ var_networkmanager_dns_mode }}' in the [main] section of - '/etc/NetworkManager/NetworkManager.conf' - ini_file: - path: /etc/NetworkManager/NetworkManager.conf +- name: NetworkManager DNS Mode Must Be Must Configured - Search for a section in + files + ansible.builtin.find: + paths: '{{item.path}}' + patterns: '{{item.pattern}}' + contains: ^\s*\[main\] + read_whole_file: true + use_regex: true + register: systemd_dropin_files_with_section + loop: + - path: '{{ ''/etc/NetworkManager/NetworkManager.conf'' | dirname }}' + pattern: '{{ ''/etc/NetworkManager/NetworkManager.conf'' | basename | regex_escape + }}' + - path: /etc/NetworkManager/conf.d + pattern: .*\.conf + when: '"NetworkManager" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed + - restrict_strategy + +- name: NetworkManager DNS Mode Must Be Must Configured - Count number of files which + contain the correct section + ansible.builtin.set_fact: + count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results + | map(attribute=''matched'') | list | map(''int'') | sum}}' + when: '"NetworkManager" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed + - restrict_strategy + +- name: NetworkManager DNS Mode Must Be Must Configured - Add missing configuration + to correct section + community.general.ini_file: + path: '{{item}}' section: main option: dns - value: '{{ var_networkmanager_dns_mode }}' - create: true - mode: 420 + value: '{{var_networkmanager_dns_mode}}' + state: present no_extra_spaces: true - when: '"NetworkManager" in ansible_facts.packages' + when: + - '"NetworkManager" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int > 0 + loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[]) + | map(attribute=''path'') | list }}' tags: - DISA-STIG-OL09-00-006002 - NIST-800-53-CM-6(b) - - configure_strategy - low_complexity - low_disruption - medium_severity - networkmanager_dns_mode - no_reboot_needed + - restrict_strategy -- name: NetworkManager DNS Mode Must Be Must Configured - Ensure Network Manager - ansible.builtin.systemd: - name: NetworkManager - state: reloaded - when: '"NetworkManager" in ansible_facts.packages' +- name: NetworkManager DNS Mode Must Be Must Configured - Add configuration to new + remediation file + community.general.ini_file: + path: /etc/NetworkManager/conf.d/complianceascode_hardening.conf + section: main + option: dns + value: '{{var_networkmanager_dns_mode}}' + state: present + no_extra_spaces: true + create: true + when: + - '"NetworkManager" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int == 0 tags: - DISA-STIG-OL09-00-006002 - NIST-800-53-CM-6(b) - - configure_strategy - low_complexity - low_disruption - medium_severity - networkmanager_dns_mode - no_reboot_needed + - restrict_strategy @@ -69429,13 +79680,11 @@ arisen. All directories in local partitions which are world-writable should be owned by root. If any world-writable directories are not owned by root, this should be investigated. Following this, the files should be deleted or assigned to root user. - CCI-000366 - CCI-001090 - SRG-OS-000480-GPOS-00227 - SRG-OS-000138-GPOS-00069 + SRG-OS-000480-GPOS-00227 + SRG-OS-000138-GPOS-00069 R54 - OL09-00-002516 - SV-271785r1092067_rule + OL09-00-002516 + SV-271785r1117267_rule Allowing a user account to own a world-writable directory is undesirable because it allows the owner of that directory to remove or replace any files that may be placed in the directory by other users. @@ -69443,9 +79692,9 @@ other users. # At least under containerized env /proc can have files w/o possilibity to # modify even as root. And touching /proc is not good idea anyways. find / -path /proc -prune -o \ - -not -fstype afs -not -fstype ceph -not -fstype cifs -not -fstype smb3 -not -fstype smbfs \ - -not -fstype sshfs -not -fstype ncpfs -not -fstype ncp -not -fstype nfs -not -fstype nfs4 \ - -not -fstype gfs -not -fstype gfs2 -not -fstype glusterfs -not -fstype gpfs \ + -not -fstype afs -not -fstype autofs -not -fstype ceph -not -fstype cifs -not -fstype smb3 \ + -not -fstype smbfs -not -fstype sshfs -not -fstype ncpfs -not -fstype ncp -not -fstype nfs \ + -not -fstype nfs4 -not -fstype gfs -not -fstype gfs2 -not -fstype glusterfs -not -fstype gpfs \ -not -fstype pvfs2 -not -fstype ocfs2 -not -fstype lustre -not -fstype davfs \ -not -fstype fuse.sshfs -type d -perm -0002 -uid +0 -exec chown root {} \; @@ -69454,6 +79703,7 @@ find / -path /proc -prune -o \ ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -69636,6 +79886,11 @@ To set the sticky bit on a world-writable directory DIR, run th amount of resources depending on the number of directories present on the system. It is not a problem in most cases, but especially systems with a large number of directories can be affected. See https://access.redhat.com/articles/6999111. + Please note that there might be cases where the rule remediation cannot fix directory permissions. +This can happen for example when running on a system with some immutable parts. +These immutable parts cannot be remediated because they are read-only. +Example of such directories can be OStree deployments located at /sysroot/ostree/deploy. +In such case, it is needed to make modifications to the underlying ostree snapshot and this is out of scope of regular rule remediation. 12 13 14 @@ -69648,7 +79903,6 @@ be affected. See https://access.redhat.com/articles/6999111DSS05.04 DSS05.07 DSS06.02 - CCI-001090 4.3.3.7.3 SR 2.1 SR 5.2 @@ -69675,25 +79929,26 @@ be affected. See https://access.redhat.com/articles/6999111A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000138-GPOS-00069 + SRG-OS-000138-GPOS-00069 R54 + 1409 2.2.6 2.2 - OL09-00-002510 - SV-271779r1092049_rule + OL09-00-002510 + SV-271779r1117267_rule Failing to set the sticky bit on public directories allows unauthorized users to delete files in the directory structure. @@ -69712,6 +79967,7 @@ and for directories requiring global read/write access. ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -69929,10 +80185,9 @@ correct its ownership with the following command: $ sudo chgrp root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without @@ -69945,6 +80200,38 @@ Software libraries also include privileged programs which execute with escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. + + +for SYSCMDDIRS in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin +do + find -L $SYSCMDDIRS ! -group root -type d -exec chgrp root '{}' \; +done + + - name: Verify that system commands directories have root as a group owner - Set group + ownership of directories that contain system commands to root + ansible.builtin.file: + path: '{{ item }}' + group: root + recurse: 'yes' + state: directory + follow: 'yes' + with_items: + - /bin + - /sbin + - /usr/bin + - /usr/sbin + - /usr/local/bin + - /usr/local/sbin + tags: + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - dir_system_commands_group_root_owned + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + @@ -69968,10 +80255,9 @@ correct its ownership with the following command: $ sudo chown root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without @@ -69984,6 +80270,37 @@ Software libraries also include privileged programs which execute with escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. + +for SYSCMDDIRS in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin +do + find -L $SYSCMDDIRS \! -user root -type d -exec chown root {} \; +done + + - name: Verify that system commands directories have root ownership - Set ownership + of directories that contain system commands to root + ansible.builtin.file: + path: '{{ item }}' + owner: root + recurse: 'yes' + state: directory + follow: 'yes' + with_items: + - /bin + - /sbin + - /usr/bin + - /usr/sbin + - /usr/local/bin + - /usr/local/sbin + tags: + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - dir_system_commands_root_owned + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + @@ -69993,7 +80310,8 @@ including upgrades and modifications. Verify Group Who Owns /etc/crypttab File - To properly set the group owner of /etc/crypttab, run the command: $ sudo chgrp root /etc/crypttab + To properly set the group owner of /etc/crypttab, run the command: +$ sudo chgrp root /etc/crypttab R50 The ownership of the /etc/crypttab file by the root group is important @@ -70001,12 +80319,31 @@ because this file hosts encrypted block devices configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the encrypted block devices configuration. - chgrp root /etc/crypttab + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/crypttab" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/crypttab +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/crypttab - stat: - path: /etc/crypttab - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_groupowner_etc_crypttab @@ -70015,11 +80352,57 @@ configuration. - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/crypttab - file: +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_crypttab_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_crypttab_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_crypttab_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crypttab + ansible.builtin.stat: path: /etc/crypttab - group: root - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/crypttab + ansible.builtin.file: + path: /etc/crypttab + follow: false + group: '{{ file_groupowner_etc_crypttab_newgroup }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_groupowner_etc_crypttab @@ -70043,22 +80426,82 @@ addresses. These files must be group-owned by root. To properly set the group owner of /boot/System.map*, run the command: -$ sudo chgrp root /boot/System.map* + + $ sudo chgrp root /boot/System.map* R29 The purpose of System.map files is primarily for debugging and profiling the kernel. Unrestricted access to these files might disclose information useful to attackers and malicious software leading to more sophisticated exploitation. - -find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -regex '^.*System\.map.*$' -exec chgrp -L root {} \; + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -regex '^.*System\.map.*$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /boot/ file(s) matching ^.*System\.map.*$ - command: find -H /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended - -regex "^.*System\.map.*$" + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_systemmap_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Set the file_groupowner_systemmap_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_systemmap_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Find /boot/ file(s) matching ^.*System\.map.*$ + ansible.builtin.command: find -P /boot/ -maxdepth 1 -type f ! -group root -regextype + posix-extended -regex "^.*System\.map.*$" register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupowner_systemmap @@ -70068,12 +80511,14 @@ find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -rege - no_reboot_needed - name: Ensure group owner on /boot/ file(s) matching ^.*System\.map.*$ - file: + ansible.builtin.file: path: '{{ item }}' - group: root + follow: false + group: '{{ file_groupowner_systemmap_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupowner_systemmap @@ -70091,7 +80536,8 @@ find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -rege Verify User Who Owns /etc/crypttab File - To properly set the owner of /etc/crypttab, run the command: $ sudo chown root /etc/crypttab + To properly set the owner of /etc/crypttab, run the command: +$ sudo chown root /etc/crypttab R50 The ownership of the /etc/crypttab file by the root user is important @@ -70099,12 +80545,31 @@ because this file hosts encrypted block devices configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the encrypted block devices configuration. - chown 0 /etc/crypttab + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/crypttab" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/crypttab +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/crypttab - stat: - path: /etc/crypttab - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_owner_etc_crypttab @@ -70113,11 +80578,39 @@ configuration. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/crypttab - file: +- name: Set the file_owner_etc_crypttab_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_crypttab_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crypttab + ansible.builtin.stat: path: /etc/crypttab - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /etc/crypttab + ansible.builtin.file: + path: /etc/crypttab + follow: false + owner: '{{ file_owner_etc_crypttab_newown }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_owner_etc_crypttab @@ -70141,22 +80634,65 @@ addresses. These files must be owned by root. To properly set the owner of /boot/System.map*, run the command: -$ sudo chown root /boot/System.map* + + $ sudo chown root /boot/System.map* R29 The purpose of System.map files is primarily for debugging and profiling the kernel. Unrestricted access to these files might disclose information useful to attackers and malicious software leading to more sophisticated exploitation. - -find -L /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*System\.map.*$' -exec chown -L 0 {} \; + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /boot/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*System\.map.*$' -exec chown --no-dereference "$newown" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /boot/ file(s) matching ^.*System\.map.*$ - command: find -H /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex - "^.*System\.map.*$" + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_owner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Set the file_owner_systemmap_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_systemmap_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Find /boot/ file(s) matching ^.*System\.map.*$ + ansible.builtin.command: find -P /boot/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*System\.map.*$" register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_owner_systemmap @@ -70166,12 +80702,14 @@ find -L /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^. - no_reboot_needed - name: Ensure owner on /boot/ file(s) matching ^.*System\.map.*$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_owner_systemmap_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_owner_systemmap @@ -70197,16 +80735,32 @@ because this file hosts encrypted block devices configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the encrypted block devices configuration. - - - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chmod u-xs,g-xwrs,o-xwrt /etc/crypttab + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/crypttab - stat: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crypttab + ansible.builtin.stat: path: /etc/crypttab register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_etc_crypttab @@ -70216,10 +80770,12 @@ chmod u-xs,g-xwrs,o-xwrt /etc/crypttab - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crypttab - file: + ansible.builtin.file: path: /etc/crypttab mode: u-xs,g-xwrs,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_permissions_etc_crypttab @@ -70249,19 +80805,35 @@ To properly set the permissions of /boot/System.map*, run The purpose of System.map files is primarily for debugging and profiling the kernel. Unrestricted access to these files might disclose information useful to attackers and malicious software leading to more sophisticated exploitation. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +find -P /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*System\.map.*$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; - -find -L /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*System\.map.*$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /boot/ file(s) - command: find -H /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype - posix-extended -regex "^.*System\.map.*$" + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Find /boot/ file(s) + ansible.builtin.command: find -P /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type + f -regextype posix-extended -regex "^.*System\.map.*$" register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_systemmap @@ -70271,12 +80843,13 @@ find -L /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-e - no_reboot_needed - name: Set permissions for /boot/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xwrs,o-xwrt state: file with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_systemmap @@ -70349,6 +80922,7 @@ See https://access.redhat.com/articles/6999111.PR.AC-4 PR.DS-5 R56 + 1409 Executable files with the SGID permission run with the privileges of the owner of the file. SGID files of uncertain provenance could allow for unprivileged users to elevate privileges. The presence of these files should be strictly controlled on the system. @@ -70416,6 +80990,7 @@ See https://access.redhat.com/articles/6999111.PR.AC-4 PR.DS-5 R56 + 1409 Executable files with the SUID permission run with the privileges of the owner of the file. SUID files of uncertain provenance could allow for unprivileged users to elevate privileges. The presence of these files should be strictly controlled on the system. @@ -70475,20 +81050,21 @@ See https://access.redhat.com/articles/6999111.A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 R54 + 1409 2.2.6 2.2 Data in world-writable files can be modified by any user on the system. In almost all @@ -70558,7 +81134,6 @@ See https://access.redhat.com/articles/6999111.DSS06.03 DSS06.06 DSS06.10 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -70641,12 +81216,12 @@ See https://access.redhat.com/articles/6999111.PR.AC-7 PR.DS-5 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R53 2.2.6 2.2 - OL09-00-002511 - SV-271780r1092052_rule + OL09-00-002511 + SV-271780r1092052_rule Unowned files do not directly imply a security problem, but they are generally a sign that something is amiss. They may be caused by an intruder, by incorrect software installation or draft software removal, or by failure to remove all files belonging to a deleted account, or @@ -70701,7 +81276,6 @@ See https://access.redhat.com/articles/6999111.DSS06.02 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -70785,12 +81359,12 @@ See https://access.redhat.com/articles/6999111.PR.DS-5 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R53 2.2.6 2.2 - OL09-00-002512 - SV-271781r1092055_rule + OL09-00-002512 + SV-271781r1092055_rule Unowned files do not directly imply a security problem, but they are generally a sign that something is amiss. They may be caused by an intruder, by incorrect software installation or draft software removal, or by failure to remove all files belonging to a deleted account, or @@ -70848,7 +81422,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_fifos # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_fifos="2" fi @@ -70894,16 +81468,12 @@ fi - reboot_required - sysctl_fs_protected_fifos -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_fifos.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(1) @@ -70915,13 +81485,57 @@ fi - reboot_required - sysctl_fs_protected_fifos -- name: Comment out any occurrences of fs.protected_fifos from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Find all files that contain + fs.protected_fifos + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_fifos\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Find all files that set + fs.protected_fifos to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_fifos\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Comment out any occurrences + of fs.protected_fifos from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_fifos replace: '#fs.protected_fifos' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -70932,8 +81546,9 @@ fi - reboot_required - sysctl_fs_protected_fifos -- name: Ensure sysctl fs.protected_fifos is set to 2 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Ensure sysctl fs.protected_fifos + is set to 2 + ansible.posix.sysctl: name: fs.protected_fifos value: '2' sysctl_file: /etc/sysctl.conf @@ -70950,6 +81565,10 @@ fi - reboot_required - sysctl_fs_protected_fifos + + + + @@ -70962,25 +81581,23 @@ fi To set the runtime status of the fs.protected_hardlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_hardlinks=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_hardlinks = 1 - CCI-002235 - CCI-002165 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) - SRG-OS-000312-GPOS-00122 - SRG-OS-000312-GPOS-00123 - SRG-OS-000324-GPOS-00125 + SRG-OS-000312-GPOS-00122 + SRG-OS-000312-GPOS-00123 + SRG-OS-000324-GPOS-00125 R14 - OL09-00-002401 - SV-271740r1091932_rule + OL09-00-002401 + SV-271740r1091932_rule By enabling this kernel parameter, users can no longer create soft or hard links to files which they do not own. Disallowing such hardlinks mitigate vulnerabilities based on insecure file system accessed by privileged programs, avoiding an @@ -71017,7 +81634,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_hardlinks # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_hardlinks="1" fi @@ -71064,16 +81681,13 @@ fi - reboot_required - sysctl_fs_protected_hardlinks -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_hardlinks.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002401 @@ -71086,13 +81700,59 @@ fi - reboot_required - sysctl_fs_protected_hardlinks -- name: Comment out any occurrences of fs.protected_hardlinks from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Find all files that + contain fs.protected_hardlinks + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_hardlinks\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Find all files that + set fs.protected_hardlinks to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_hardlinks\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Comment out any occurrences + of fs.protected_hardlinks from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_hardlinks replace: '#fs.protected_hardlinks' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002401 - NIST-800-53-AC-6(1) @@ -71104,8 +81764,9 @@ fi - reboot_required - sysctl_fs_protected_hardlinks -- name: Ensure sysctl fs.protected_hardlinks is set to 1 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Ensure sysctl fs.protected_hardlinks + is set to 1 + ansible.posix.sysctl: name: fs.protected_hardlinks value: '1' sysctl_file: /etc/sysctl.conf @@ -71123,6 +81784,10 @@ fi - reboot_required - sysctl_fs_protected_hardlinks + + + + @@ -71174,7 +81839,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_regular # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_regular="2" fi @@ -71220,16 +81885,13 @@ fi - reboot_required - sysctl_fs_protected_regular -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_regular.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(1) @@ -71241,13 +81903,57 @@ fi - reboot_required - sysctl_fs_protected_regular -- name: Comment out any occurrences of fs.protected_regular from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Find all files that + contain fs.protected_regular + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_regular\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Find all files that + set fs.protected_regular to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_regular\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Comment out any + occurrences of fs.protected_regular from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_regular replace: '#fs.protected_regular' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -71258,8 +81964,9 @@ fi - reboot_required - sysctl_fs_protected_regular -- name: Ensure sysctl fs.protected_regular is set to 2 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Ensure sysctl fs.protected_regular + is set to 2 + ansible.posix.sysctl: name: fs.protected_regular value: '2' sysctl_file: /etc/sysctl.conf @@ -71276,6 +81983,10 @@ fi - reboot_required - sysctl_fs_protected_regular + + + + @@ -71288,25 +81999,23 @@ fi To set the runtime status of the fs.protected_symlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_symlinks=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_symlinks = 1 - CCI-002235 - CCI-002165 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) - SRG-OS-000312-GPOS-00122 - SRG-OS-000312-GPOS-00123 - SRG-OS-000324-GPOS-00125 + SRG-OS-000312-GPOS-00122 + SRG-OS-000312-GPOS-00123 + SRG-OS-000324-GPOS-00125 R14 - OL09-00-002402 - SV-271741r1091935_rule + OL09-00-002402 + SV-271741r1091935_rule By enabling this kernel parameter, symbolic links are permitted to be followed only when outside a sticky world-writable directory, or when the UID of the link and follower match, or when the directory owner matches the symlink's owner. @@ -71345,7 +82054,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_symlinks # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_symlinks="1" fi @@ -71392,16 +82101,12 @@ fi - reboot_required - sysctl_fs_protected_symlinks -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_symlinks.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002402 @@ -71414,13 +82119,59 @@ fi - reboot_required - sysctl_fs_protected_symlinks -- name: Comment out any occurrences of fs.protected_symlinks from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Find all files that contain + fs.protected_symlinks + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_symlinks\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Find all files that set + fs.protected_symlinks to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_symlinks\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Comment out any occurrences + of fs.protected_symlinks from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_symlinks replace: '#fs.protected_symlinks' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002402 - NIST-800-53-AC-6(1) @@ -71432,8 +82183,9 @@ fi - reboot_required - sysctl_fs_protected_symlinks -- name: Ensure sysctl fs.protected_symlinks is set to 1 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Ensure sysctl fs.protected_symlinks + is set to 1 + ansible.posix.sysctl: name: fs.protected_symlinks value: '1' sysctl_file: /etc/sysctl.conf @@ -71451,6 +82203,10 @@ fi - reboot_required - sysctl_fs_protected_symlinks + + + + @@ -71468,23 +82224,53 @@ read access to the shadow file allows malicious attacks a passwords, and should never be enabled. Verify Group Who Owns Backup group File - To properly set the group owner of /etc/group-, run the command: $ sudo chgrp root /etc/group- + To properly set the group owner of /etc/group-, run the command: +$ sudo chgrp root /etc/group- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002533 - SV-271795r1092097_rule + OL09-00-002533 + SV-271795r1092097_rule The /etc/group- file is a backup file of /etc/group, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chgrp 0 /etc/group- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/group-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/group- +fi + +fi - - name: Test for existence /etc/group- - stat: + - name: Set the file_groupowner_backup_etc_group_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_group_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002533 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group- + ansible.builtin.stat: path: /etc/group- register: file_exists tags: @@ -71500,10 +82286,11 @@ Protection of this file is important for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/group- - file: +- name: Ensure group owner on /etc/group- + ansible.builtin.file: path: /etc/group- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_group_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002533 @@ -71527,20 +82314,48 @@ Protection of this file is important for system security. Verify Group Who Owns Backup gshadow File - To properly set the group owner of /etc/gshadow-, run the command: $ sudo chgrp root /etc/gshadow- + To properly set the group owner of /etc/gshadow-, run the command: +$ sudo chgrp root /etc/gshadow- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 - OL09-00-002539 - SV-271801r1092115_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002539 + SV-271801r1092115_rule The /etc/gshadow- file is a backup of /etc/gshadow, and as such, it contains group password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/gshadow- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/gshadow-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/gshadow- +fi + +fi - - name: Test for existence /etc/gshadow- - stat: + - name: Set the file_groupowner_backup_etc_gshadow_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_gshadow_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002539 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_groupowner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow- + ansible.builtin.stat: path: /etc/gshadow- register: file_exists tags: @@ -71554,10 +82369,11 @@ it contains group password hashes. Protection of this file is critical for syste - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/gshadow- - file: +- name: Ensure group owner on /etc/gshadow- + ansible.builtin.file: path: /etc/gshadow- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_gshadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002539 @@ -71579,23 +82395,53 @@ it contains group password hashes. Protection of this file is critical for syste Verify Group Who Owns Backup passwd File - To properly set the group owner of /etc/passwd-, run the command: $ sudo chgrp root /etc/passwd- + To properly set the group owner of /etc/passwd-, run the command: +$ sudo chgrp root /etc/passwd- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002545 - SV-271807r1092133_rule + OL09-00-002545 + SV-271807r1092133_rule The /etc/passwd- file is a backup file of /etc/passwd, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security. - chgrp 0 /etc/passwd- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/passwd-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/passwd- +fi + +fi - - name: Test for existence /etc/passwd- - stat: + - name: Set the file_groupowner_backup_etc_passwd_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_passwd_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002545 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd- + ansible.builtin.stat: path: /etc/passwd- register: file_exists tags: @@ -71611,10 +82457,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/passwd- - file: +- name: Ensure group owner on /etc/passwd- + ansible.builtin.file: path: /etc/passwd- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_passwd_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002545 @@ -71638,22 +82485,51 @@ Protection of this file is critical for system security. Verify User Who Owns Backup shadow File - To properly set the group owner of /etc/shadow-, run the command: $ sudo chgrp root /etc/shadow- + To properly set the group owner of /etc/shadow-, run the command: +$ sudo chgrp root /etc/shadow- - CCI-000366 Req-8.7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002551 - SV-271813r1092151_rule + OL09-00-002551 + SV-271813r1092151_rule The /etc/shadow- file is a backup file of /etc/shadow, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/shadow- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/shadow-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/shadow- +fi + +fi - - name: Test for existence /etc/shadow- - stat: + - name: Set the file_groupowner_backup_etc_shadow_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_shadow_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002551 + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow- + ansible.builtin.stat: path: /etc/shadow- register: file_exists tags: @@ -71668,10 +82544,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/shadow- - file: +- name: Ensure group owner on /etc/shadow- + ansible.builtin.file: path: /etc/shadow- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_shadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002551 @@ -71694,7 +82571,8 @@ Protection of this file is critical for system security. Verify Group Who Owns group File - To properly set the group owner of /etc/group, run the command: $ sudo chgrp root /etc/group + To properly set the group owner of /etc/group, run the command: +$ sudo chgrp root /etc/group 12 13 @@ -71709,7 +82587,6 @@ Protection of this file is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -71736,32 +82613,63 @@ Protection of this file is critical for system security. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002532 - SV-271794r1092094_rule + OL09-00-002532 + SV-271794r1092094_rule The /etc/group file contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chgrp 0 /etc/group + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/group" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/group +fi + +fi - - name: Test for existence /etc/group - stat: + - name: Set the file_groupowner_etc_group_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_group_newgroup: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002532 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group + ansible.builtin.stat: path: /etc/group register: file_exists tags: @@ -71779,10 +82687,11 @@ on the system. Protection of this file is important for system security. Verify Group Who Owns gshadow File - To properly set the group owner of /etc/gshadow, run the command: $ sudo chgrp root /etc/gshadow + To properly set the group owner of /etc/gshadow, run the command: +$ sudo chgrp root /etc/gshadow 12 13 @@ -71822,7 +82732,6 @@ on the system. Protection of this file is important for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -71849,29 +82758,56 @@ on the system. Protection of this file is important for system security.A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002538 - SV-271800r1092112_rule + OL09-00-002538 + SV-271800r1092112_rule The /etc/gshadow file contains group password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/gshadow + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/gshadow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/gshadow +fi + +fi - - name: Test for existence /etc/gshadow - stat: + - name: Set the file_groupowner_etc_gshadow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_gshadow_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002538 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow + ansible.builtin.stat: path: /etc/gshadow register: file_exists tags: @@ -71885,10 +82821,11 @@ is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/gshadow - file: +- name: Ensure group owner on /etc/gshadow + ansible.builtin.file: path: /etc/gshadow - group: '0' + follow: false + group: '{{ file_groupowner_etc_gshadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002538 @@ -71910,7 +82847,8 @@ is critical for system security. Verify Group Who Owns passwd File - To properly set the group owner of /etc/passwd, run the command: $ sudo chgrp root /etc/passwd + To properly set the group owner of /etc/passwd, run the command: +$ sudo chgrp root /etc/passwd 12 13 @@ -71925,7 +82863,6 @@ is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -71952,32 +82889,63 @@ is critical for system security. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002544 - SV-271806r1092130_rule + OL09-00-002544 + SV-271806r1092130_rule The /etc/passwd file contains information about the users that are configured on the system. Protection of this file is critical for system security. - chgrp 0 /etc/passwd + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/passwd" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/passwd +fi + +fi - - name: Test for existence /etc/passwd - stat: + - name: Set the file_groupowner_etc_passwd_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_passwd_newgroup: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002544 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd + ansible.builtin.stat: path: /etc/passwd register: file_exists tags: @@ -71995,10 +82963,11 @@ the system. Protection of this file is critical for system security. Verify Group Who Owns shadow File - To properly set the group owner of /etc/shadow, run the command: $ sudo chgrp root /etc/shadow + To properly set the group owner of /etc/shadow, run the command: +$ sudo chgrp root /etc/shadow 12 13 @@ -72039,7 +83009,6 @@ the system. Protection of this file is critical for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72066,32 +83035,63 @@ the system. Protection of this file is critical for system security.A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002550 - SV-271812r1092148_rule + OL09-00-002550 + SV-271812r1092148_rule The /etc/shadow file stores password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/shadow + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/shadow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/shadow +fi + +fi - - name: Test for existence /etc/shadow - stat: + - name: Set the file_groupowner_etc_shadow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_shadow_newgroup: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002550 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow + ansible.builtin.stat: path: /etc/shadow register: file_exists tags: @@ -72109,10 +83109,11 @@ critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/shadow - file: +- name: Ensure group owner on /etc/shadow + ansible.builtin.file: path: /etc/shadow - group: '0' + follow: false + group: '{{ file_groupowner_etc_shadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - CJIS-5.5.2.2 @@ -72140,17 +83141,44 @@ critical for system security. Verify Group Who Owns /etc/shells File To properly set the group owner of /etc/shells, run the command: -$ sudo chgrp root /etc/shells + + $ sudo chgrp root /etc/shells AC-3 MP-2 R50 The /etc/shells file contains the list of full pathnames to shells on the system. Since this file is used by many system programs this file should be protected. - chgrp 0 /etc/shells + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/shells" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/shells +fi + +fi - - name: Test for existence /etc/shells - stat: + - name: Set the file_groupowner_etc_shells_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_shells_newgroup: '0' + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_groupowner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shells + ansible.builtin.stat: path: /etc/shells register: file_exists tags: @@ -72163,10 +83191,11 @@ Since this file is used by many system programs this file should be protected. Verify User Who Owns Backup group File - To properly set the owner of /etc/group-, run the command: $ sudo chown root /etc/group- + To properly set the owner of /etc/group-, run the command: +$ sudo chown root /etc/group- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002535 - SV-271797r1092103_rule + OL09-00-002535 + SV-271797r1092103_rule The /etc/group- file is a backup file of /etc/group, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chown 0 /etc/group- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/group-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/group- +fi + +fi - - name: Test for existence /etc/group- - stat: + - name: Set the file_owner_backup_etc_group_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_group_newown: '0' + tags: + - DISA-STIG-OL09-00-002535 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group- + ansible.builtin.stat: path: /etc/group- register: file_exists tags: @@ -72219,10 +83277,11 @@ Protection of this file is important for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/group- - file: +- name: Ensure owner on /etc/group- + ansible.builtin.file: path: /etc/group- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_group_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002535 @@ -72246,20 +83305,47 @@ Protection of this file is important for system security. Verify User Who Owns Backup gshadow File - To properly set the owner of /etc/gshadow-, run the command: $ sudo chown root /etc/gshadow- + To properly set the owner of /etc/gshadow-, run the command: +$ sudo chown root /etc/gshadow- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 - OL09-00-002541 - SV-271803r1092121_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002541 + SV-271803r1092121_rule The /etc/gshadow- file is a backup of /etc/gshadow, and as such, it contains group password hashes. Protection of this file is critical for system security. - chown 0 /etc/gshadow- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/gshadow-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/gshadow- +fi + +fi - - name: Test for existence /etc/gshadow- - stat: + - name: Set the file_owner_backup_etc_gshadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_gshadow_newown: '0' + tags: + - DISA-STIG-OL09-00-002541 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_owner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow- + ansible.builtin.stat: path: /etc/gshadow- register: file_exists tags: @@ -72273,10 +83359,11 @@ it contains group password hashes. Protection of this file is critical for syste - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/gshadow- - file: +- name: Ensure owner on /etc/gshadow- + ansible.builtin.file: path: /etc/gshadow- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_gshadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002541 @@ -72298,23 +83385,52 @@ it contains group password hashes. Protection of this file is critical for syste Verify User Who Owns Backup passwd File - To properly set the owner of /etc/passwd-, run the command: $ sudo chown root /etc/passwd- + To properly set the owner of /etc/passwd-, run the command: +$ sudo chown root /etc/passwd- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002547 - SV-271809r1092139_rule + OL09-00-002547 + SV-271809r1092139_rule The /etc/passwd- file is a backup file of /etc/passwd, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security. - chown 0 /etc/passwd- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/passwd-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/passwd- +fi + +fi - - name: Test for existence /etc/passwd- - stat: + - name: Set the file_owner_backup_etc_passwd_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_passwd_newown: '0' + tags: + - DISA-STIG-OL09-00-002547 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd- + ansible.builtin.stat: path: /etc/passwd- register: file_exists tags: @@ -72330,10 +83446,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/passwd- - file: +- name: Ensure owner on /etc/passwd- + ansible.builtin.file: path: /etc/passwd- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_passwd_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002547 @@ -72357,23 +83474,52 @@ Protection of this file is critical for system security. Verify Group Who Owns Backup shadow File - To properly set the owner of /etc/shadow-, run the command: $ sudo chown root /etc/shadow- + To properly set the owner of /etc/shadow-, run the command: +$ sudo chown root /etc/shadow- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002553 - SV-271815r1092157_rule + OL09-00-002553 + SV-271815r1092157_rule The /etc/shadow- file is a backup file of /etc/shadow, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security. - chown 0 /etc/shadow- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/shadow-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/shadow- +fi + +fi - - name: Test for existence /etc/shadow- - stat: + - name: Set the file_owner_backup_etc_shadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_shadow_newown: '0' + tags: + - DISA-STIG-OL09-00-002553 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow- + ansible.builtin.stat: path: /etc/shadow- register: file_exists tags: @@ -72389,10 +83535,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/shadow- - file: +- name: Ensure owner on /etc/shadow- + ansible.builtin.file: path: /etc/shadow- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_shadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002553 @@ -72416,7 +83563,8 @@ Protection of this file is critical for system security. Verify User Who Owns group File - To properly set the owner of /etc/group, run the command: $ sudo chown root /etc/group + To properly set the owner of /etc/group, run the command: +$ sudo chown root /etc/group 12 13 @@ -72431,7 +83579,6 @@ Protection of this file is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72458,32 +83605,63 @@ Protection of this file is critical for system security. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002534 - SV-271796r1092100_rule + OL09-00-002534 + SV-271796r1092100_rule The /etc/group file contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chown 0 /etc/group + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/group" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/group +fi + +fi - - name: Test for existence /etc/group - stat: + - name: Set the file_owner_etc_group_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_group_newown: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002534 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group + ansible.builtin.stat: path: /etc/group register: file_exists tags: @@ -72501,10 +83679,11 @@ on the system. Protection of this file is important for system security. Verify User Who Owns gshadow File - To properly set the owner of /etc/gshadow, run the command: $ sudo chown root /etc/gshadow + To properly set the owner of /etc/gshadow, run the command: +$ sudo chown root /etc/gshadow 12 13 @@ -72544,7 +83724,6 @@ on the system. Protection of this file is important for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72571,29 +83750,56 @@ on the system. Protection of this file is important for system security.A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002540 - SV-271802r1092118_rule + OL09-00-002540 + SV-271802r1092118_rule The /etc/gshadow file contains group password hashes. Protection of this file is critical for system security. - chown 0 /etc/gshadow + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/gshadow" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/gshadow +fi + +fi - - name: Test for existence /etc/gshadow - stat: + - name: Set the file_owner_etc_gshadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_gshadow_newown: '0' + tags: + - DISA-STIG-OL09-00-002540 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow + ansible.builtin.stat: path: /etc/gshadow register: file_exists tags: @@ -72607,10 +83813,11 @@ is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/gshadow - file: +- name: Ensure owner on /etc/gshadow + ansible.builtin.file: path: /etc/gshadow - owner: '0' + follow: false + owner: '{{ file_owner_etc_gshadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002540 @@ -72632,7 +83839,8 @@ is critical for system security. Verify User Who Owns passwd File - To properly set the owner of /etc/passwd, run the command: $ sudo chown root /etc/passwd + To properly set the owner of /etc/passwd, run the command: +$ sudo chown root /etc/passwd 12 13 @@ -72647,7 +83855,6 @@ is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72674,32 +83881,63 @@ is critical for system security. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002546 - SV-271808r1092136_rule + OL09-00-002546 + SV-271808r1092136_rule The /etc/passwd file contains information about the users that are configured on the system. Protection of this file is critical for system security. - chown 0 /etc/passwd + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/passwd" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/passwd +fi + +fi - - name: Test for existence /etc/passwd - stat: + - name: Set the file_owner_etc_passwd_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_passwd_newown: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002546 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd + ansible.builtin.stat: path: /etc/passwd register: file_exists tags: @@ -72717,10 +83955,11 @@ the system. Protection of this file is critical for system security. Verify User Who Owns shadow File - To properly set the owner of /etc/shadow, run the command: $ sudo chown root /etc/shadow + To properly set the owner of /etc/shadow, run the command: +$ sudo chown root /etc/shadow 12 13 @@ -72761,7 +84001,6 @@ the system. Protection of this file is critical for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72788,35 +84027,66 @@ the system. Protection of this file is critical for system security.A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002552 - SV-271814r1092154_rule + OL09-00-002552 + SV-271814r1092154_rule The /etc/shadow file contains the list of local system accounts and stores password hashes. Protection of this file is critical for system security. Failure to give ownership of this file to root provides the designated owner with access to sensitive information which could weaken the system security posture. - chown 0 /etc/shadow + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/shadow" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/shadow +fi + +fi - - name: Test for existence /etc/shadow - stat: + - name: Set the file_owner_etc_shadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_shadow_newown: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002552 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow + ansible.builtin.stat: path: /etc/shadow register: file_exists tags: @@ -72834,10 +84104,11 @@ which could weaken the system security posture. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/shadow - file: +- name: Ensure owner on /etc/shadow + ansible.builtin.file: path: /etc/shadow - owner: '0' + follow: false + owner: '{{ file_owner_etc_shadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - CJIS-5.5.2.2 @@ -72865,17 +84136,44 @@ which could weaken the system security posture. Verify Who Owns /etc/shells File To properly set the owner of /etc/shells, run the command: -$ sudo chown root /etc/shells + + $ sudo chown root /etc/shells AC-3 MP-2 R50 The /etc/shells file contains the list of full pathnames to shells on the system. Since this file is used by many system programs this file should be protected. - chown 0 /etc/shells + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/shells" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/shells +fi + +fi - - name: Test for existence /etc/shells - stat: + - name: Set the file_owner_etc_shells_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_shells_newown: '0' + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_owner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shells + ansible.builtin.stat: path: /etc/shells register: file_exists tags: @@ -72888,10 +84186,11 @@ Since this file is used by many system programs this file should be protected./etc/group-, run the command: $ sudo chmod 0644 /etc/group- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002537 - SV-271799r1092109_rule + OL09-00-002537 + SV-271799r1092109_rule The /etc/group- file is a backup file of /etc/group, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security. @@ -72934,7 +84232,7 @@ Protection of this file is important for system security. chmod u-xs,g-xws,o-xwt /etc/group- - name: Test for existence /etc/group- - stat: + ansible.builtin.stat: path: /etc/group- register: file_exists tags: @@ -72951,7 +84249,7 @@ chmod u-xs,g-xws,o-xwt /etc/group- - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/group- - file: + ansible.builtin.file: path: /etc/group- mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -72981,11 +84279,10 @@ chmod u-xs,g-xws,o-xwt /etc/group- To properly set the permissions of /etc/gshadow-, run the command: $ sudo chmod 0000 /etc/gshadow- - CCI-000366 AC-6 (1) - SRG-OS-000480-GPOS-00227 - OL09-00-002543 - SV-271805r1092127_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002543 + SV-271805r1092127_rule The /etc/gshadow- file is a backup of /etc/gshadow, and as such, it contains group password hashes. Protection of this file is critical for system security. @@ -72995,7 +84292,7 @@ it contains group password hashes. Protection of this file is critical for syste chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- - name: Test for existence /etc/gshadow- - stat: + ansible.builtin.stat: path: /etc/gshadow- register: file_exists tags: @@ -73009,7 +84306,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow- - file: + ansible.builtin.file: path: /etc/gshadow- mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73036,14 +84333,13 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- To properly set the permissions of /etc/passwd-, run the command: $ sudo chmod 0644 /etc/passwd- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002549 - SV-271811r1092145_rule + OL09-00-002549 + SV-271811r1092145_rule The /etc/passwd- file is a backup file of /etc/passwd, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security. @@ -73054,7 +84350,7 @@ Protection of this file is critical for system security. chmod u-xs,g-xws,o-xwt /etc/passwd- - name: Test for existence /etc/passwd- - stat: + ansible.builtin.stat: path: /etc/passwd- register: file_exists tags: @@ -73071,7 +84367,7 @@ chmod u-xs,g-xws,o-xwt /etc/passwd- - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd- - file: + ansible.builtin.file: path: /etc/passwd- mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73101,14 +84397,13 @@ chmod u-xs,g-xws,o-xwt /etc/passwd- To properly set the permissions of /etc/shadow-, run the command: $ sudo chmod 0000 /etc/shadow- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002554 - SV-271816r1092160_rule + OL09-00-002554 + SV-271816r1092160_rule The /etc/shadow- file is a backup file of /etc/shadow, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security. @@ -73119,7 +84414,7 @@ Protection of this file is critical for system security. chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow- - name: Test for existence /etc/shadow- - stat: + ansible.builtin.stat: path: /etc/shadow- register: file_exists tags: @@ -73136,7 +84431,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow- - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow- - file: + ansible.builtin.file: path: /etc/shadow- mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73179,7 +84474,6 @@ To properly set the permissions of /etc/group, run the co DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73206,26 +84500,26 @@ To properly set the permissions of /etc/group, run the co A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002536 - SV-271798r1092106_rule + OL09-00-002536 + SV-271798r1092106_rule The /etc/group file contains information regarding groups that are configured on the system. Protection of this file is important for system security. @@ -73235,7 +84529,7 @@ on the system. Protection of this file is important for system security. - name: Test for existence /etc/group - stat: + ansible.builtin.stat: path: /etc/group register: file_exists tags: @@ -73254,7 +84548,7 @@ chmod u-xs,g-xws,o-xwt /etc/group - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/group - file: + ansible.builtin.file: path: /etc/group mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73298,7 +84592,6 @@ To properly set the permissions of /etc/gshadow, run the DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73325,23 +84618,23 @@ To properly set the permissions of /etc/gshadow, run the A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002542 - SV-271804r1092124_rule + OL09-00-002542 + SV-271804r1092124_rule The /etc/gshadow file contains group password hashes. Protection of this file is critical for system security. @@ -73351,7 +84644,7 @@ is critical for system security. chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow - name: Test for existence /etc/gshadow - stat: + ansible.builtin.stat: path: /etc/gshadow register: file_exists tags: @@ -73366,7 +84659,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow - file: + ansible.builtin.file: path: /etc/gshadow mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73407,7 +84700,6 @@ To properly set the permissions of /etc/passwd, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73434,26 +84726,26 @@ To properly set the permissions of /etc/passwd, run the c A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002548 - SV-271810r1092142_rule + OL09-00-002548 + SV-271810r1092142_rule If the /etc/passwd file is writable by a group-owner or the world the risk of its compromise is increased. The file contains the list of accounts on the system and associated information, and protection of this file @@ -73465,7 +84757,7 @@ is critical for system security. chmod u-xs,g-xws,o-xwt /etc/passwd - name: Test for existence /etc/passwd - stat: + ansible.builtin.stat: path: /etc/passwd register: file_exists tags: @@ -73484,7 +84776,7 @@ chmod u-xs,g-xws,o-xwt /etc/passwd - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd - file: + ansible.builtin.file: path: /etc/passwd mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73529,7 +84821,6 @@ To properly set the permissions of /etc/shadow, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73556,26 +84847,26 @@ To properly set the permissions of /etc/shadow, run the c A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002555 - SV-271817r1092163_rule + OL09-00-002555 + SV-271817r1092163_rule The /etc/shadow file contains the list of local system accounts and stores password hashes. Protection of this file is critical for system security. Failure to give ownership of this file @@ -73588,7 +84879,7 @@ which could weaken the system security posture. chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow - name: Test for existence /etc/shadow - stat: + ansible.builtin.stat: path: /etc/shadow register: file_exists tags: @@ -73607,7 +84898,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow - file: + ansible.builtin.file: path: /etc/shadow mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73651,7 +84942,7 @@ Since this file is used by many system programs this file should be protected. - name: Test for existence /etc/shells - stat: + ansible.builtin.stat: path: /etc/shells register: file_exists tags: @@ -73665,7 +84956,7 @@ chmod u-xs,g-xws,o-xwt /etc/shells - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/shells - file: + ansible.builtin.file: path: /etc/shells mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73694,23 +84985,47 @@ messages in the system and should only be accessed by authorized personnel. Verify Group Who Owns /var/log Directory - To properly set the group owner of /var/log, run the command: $ sudo chgrp root /var/log + To properly set the group owner of /var/log, run the command: +$ sudo chgrp root /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - OL09-00-002560 - SV-271818r1092166_rule + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002560 + SV-271818r1092166_rule The /var/log directory contains files with logs of error messages in the system and should only be accessed by authorized personnel. - find -H /var/log/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /var/log/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi - - name: Ensure group owner on /var/log/ - file: + - name: Set the file_groupowner_var_log_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_var_log_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002560 + - configure_strategy + - file_groupowner_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /var/log/ + ansible.builtin.file: path: /var/log/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_var_log_newgroup }}' tags: - DISA-STIG-OL09-00-002560 - configure_strategy @@ -73729,18 +85044,44 @@ personnel. Verify Group Who Owns /var/log/messages File - To properly set the group owner of /var/log/messages, run the command: $ sudo chgrp root /var/log/messages + To properly set the group owner of /var/log/messages, run the command: +$ sudo chgrp root /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - OL09-00-002563 - SV-271821r1092175_rule + SRG-OS-000206-GPOS-00084 + OL09-00-002563 + SV-271821r1092175_rule The /var/log/messages file contains logs of error messages in the system and should only be accessed by authorized personnel. - chgrp 0 /var/log/messages + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/var/log/messages" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /var/log/messages +fi + +fi - - name: Test for existence /var/log/messages - stat: + - name: Set the file_groupowner_var_log_messages_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_var_log_messages_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002563 + - configure_strategy + - file_groupowner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /var/log/messages + ansible.builtin.stat: path: /var/log/messages register: file_exists tags: @@ -73752,10 +85093,11 @@ the system and should only be accessed by authorized personnel. Verify Group Who Owns /var/log/syslog File - To properly set the group owner of /var/log/syslog, run the command: $ sudo chgrp adm /var/log/syslog + To properly set the group owner of /var/log/syslog, run the command: +$ sudo chgrp adm /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 + SRG-OS-000206-GPOS-00084 The /var/log/syslog file contains logs of error messages in the system and should only be accessed by authorized personnel. - chgrp 4 /var/log/syslog + + # Remediation is applicable only in certain platforms +if rpm --quiet -q rsyslog; then + +newgroup="" +if getent group "4" >/dev/null 2>&1; then + newgroup="4" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "4 is not a defined group on the system" +else +if ! stat -c "%g %G" "/var/log/syslog" | grep -E -w -q "4"; then + chgrp --no-dereference "$newgroup" /var/log/syslog +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_groupowner_var_log_syslog @@ -73795,11 +85156,40 @@ the system and should only be accessed by authorized personnel. Verify User Who Owns /var/log Directory - To properly set the owner of /var/log, run the command: $ sudo chown root /var/log + To properly set the owner of /var/log, run the command: +$ sudo chown root /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - OL09-00-002561 - SV-271819r1092169_rule + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002561 + SV-271819r1092169_rule The /var/log directory contains files with logs of error messages in the system and should only be accessed by authorized personnel. - find -H /var/log/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /var/log/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi - - name: Ensure owner on directory /var/log/ - file: + - name: Set the file_owner_var_log_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_var_log_newown: '0' + tags: + - DISA-STIG-OL09-00-002561 + - configure_strategy + - file_owner_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /var/log/ + ansible.builtin.file: path: /var/log/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_var_log_newown }}' tags: - DISA-STIG-OL09-00-002561 - configure_strategy @@ -73852,18 +85266,43 @@ personnel. Verify User Who Owns /var/log/messages File - To properly set the owner of /var/log/messages, run the command: $ sudo chown root /var/log/messages + To properly set the owner of /var/log/messages, run the command: +$ sudo chown root /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - OL09-00-002564 - SV-271822r1092178_rule + SRG-OS-000206-GPOS-00084 + OL09-00-002564 + SV-271822r1092178_rule The /var/log/messages file contains logs of error messages in the system and should only be accessed by authorized personnel. - chown 0 /var/log/messages + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/var/log/messages" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /var/log/messages +fi + +fi - - name: Test for existence /var/log/messages - stat: + - name: Set the file_owner_var_log_messages_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_var_log_messages_newown: '0' + tags: + - DISA-STIG-OL09-00-002564 + - configure_strategy + - file_owner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /var/log/messages + ansible.builtin.stat: path: /var/log/messages register: file_exists tags: @@ -73875,10 +85314,11 @@ the system and should only be accessed by authorized personnel. Verify User Who Owns /var/log/syslog File - To properly set the owner of /var/log/syslog, run the command: $ sudo chown syslog /var/log/syslog + To properly set the owner of /var/log/syslog, run the command: +$ sudo chown syslog /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 + SRG-OS-000206-GPOS-00084 The /var/log/syslog file contains logs of error messages in the system and should only be accessed by authorized personnel. - chown 104 /var/log/syslog + + # Remediation is applicable only in certain platforms +if rpm --quiet -q rsyslog; then + +newown="" +if id "syslog" >/dev/null 2>&1; then + newown="syslog" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "syslog is not a defined user on the system" +else +if ! stat -c "%u %U" "/var/log/syslog" | grep -E -w -q "syslog"; then + chown --no-dereference "$newown" /var/log/syslog +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_owner_var_log_syslog @@ -73918,11 +85377,55 @@ the system and should only be accessed by authorized personnel./var/log, run the command: $ sudo chmod 0755 /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - OL09-00-002562 - SV-271820r1092172_rule + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002562 + SV-271820r1092172_rule The /var/log directory contains files with logs of error messages in the system and should only be accessed by authorized personnel. @@ -73956,10 +85458,11 @@ personnel. -find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; +find -H /var/log/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - name: Find /var/log/ file(s) - command: 'find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /var/log/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -73974,7 +85477,7 @@ find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws, - no_reboot_needed - name: Set permissions for /var/log/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74000,22 +85503,21 @@ find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws, Verify Permissions on /var/log/messages File To properly set the permissions of /var/log/messages, run the command: -$ sudo chmod 0600 /var/log/messages +$ sudo chmod 0640 /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - OL09-00-002565 - SV-271823r1092181_rule + SRG-OS-000206-GPOS-00084 + OL09-00-002565 + SV-271823r1092181_rule The /var/log/messages file contains logs of error messages in the system and should only be accessed by authorized personnel. -chmod u-xs,g-xwrs,o-xwrt /var/log/messages +chmod u-xs,g-xws,o-xwrt /var/log/messages - name: Test for existence /var/log/messages - stat: + ansible.builtin.stat: path: /var/log/messages register: file_exists tags: @@ -74027,10 +85529,10 @@ chmod u-xs,g-xwrs,o-xwrt /var/log/messages - medium_severity - no_reboot_needed -- name: Ensure permission u-xs,g-xwrs,o-xwrt on /var/log/messages - file: +- name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/messages + ansible.builtin.file: path: /var/log/messages - mode: u-xs,g-xwrs,o-xwrt + mode: u-xs,g-xws,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002565 @@ -74054,8 +85556,7 @@ chmod u-xs,g-xwrs,o-xwrt /var/log/messages To properly set the permissions of /var/log/syslog, run the command: $ sudo chmod 0640 /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 + SRG-OS-000206-GPOS-00084 The /var/log/syslog file contains logs of error messages in the system and should only be accessed by authorized personnel. @@ -74065,7 +85566,7 @@ the system and should only be accessed by authorized personnel. - name: Test for existence /var/log/syslog - stat: + ansible.builtin.stat: path: /var/log/syslog register: file_exists tags: @@ -74077,7 +85578,7 @@ chmod u-xs,g-xws,o-xwrt /var/log/syslog - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/syslog - file: + ansible.builtin.file: path: /var/log/syslog mode: u-xs,g-xws,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -74122,27 +85623,53 @@ ownership with the following command: $ sudo chgrp root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002520 - SV-271786r1092070_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002520 + SV-271786r1092070_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Proper ownership of library directories is necessary to protect the integrity of the system. - find -H /lib/ -type d -exec chgrp -L 0 {} \; -find -H /lib64/ -type d -exec chgrp -L 0 {} \; -find -H /usr/lib/ -type d -exec chgrp -L 0 {} \; -find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /lib/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; +find -P /lib64/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib64/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi - - name: Ensure group owner on /lib/ recursively - file: + - name: Set the dir_group_ownership_library_dirs_newgroup variable if represented + by gid + ansible.builtin.set_fact: + dir_group_ownership_library_dirs_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002520 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_group_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /lib/ recursively + ansible.builtin.file: path: /lib/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74155,11 +85682,12 @@ find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; - no_reboot_needed - name: Ensure group owner on /lib64/ recursively - file: + ansible.builtin.file: path: /lib64/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74172,11 +85700,12 @@ find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; - no_reboot_needed - name: Ensure group owner on /usr/lib/ recursively - file: + ansible.builtin.file: path: /usr/lib/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74189,11 +85718,12 @@ find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; - no_reboot_needed - name: Ensure group owner on /usr/lib64/ recursively - file: + ansible.builtin.file: path: /usr/lib64/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74227,24 +85757,46 @@ following command: $ sudo chown root DIR - CCI-001495 - SRG-OS-000258-GPOS-00099 + SRG-OS-000258-GPOS-00099 System binaries are executed by privileged users as well as system services, and restrictive permissions are necessary to ensure that their execution of these programs cannot be co-opted. - find -H /bin/ -type d -exec chown -L 0 {} \; -find -H /sbin/ -type d -exec chown -L 0 {} \; -find -H /usr/bin/ -type d -exec chown -L 0 {} \; -find -H /usr/sbin/ -type d -exec chown -L 0 {} \; -find -H /usr/local/bin/ -type d -exec chown -L 0 {} \; -find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /bin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /sbin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/bin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/sbin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/local/bin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/local/sbin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi - - name: Ensure owner on directory /bin/ recursively - file: + - name: Set the dir_ownership_binary_dirs_newown variable if represented by uid + ansible.builtin.set_fact: + dir_ownership_binary_dirs_newown: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /bin/ recursively + ansible.builtin.file: path: /bin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74254,11 +85806,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /sbin/ recursively - file: + ansible.builtin.file: path: /sbin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74268,11 +85821,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/bin/ recursively - file: + ansible.builtin.file: path: /usr/bin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74282,11 +85836,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/sbin/ recursively - file: + ansible.builtin.file: path: /usr/sbin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74296,11 +85851,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/local/bin/ recursively - file: + ansible.builtin.file: path: /usr/local/bin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74310,11 +85866,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/local/sbin/ recursively - file: + ansible.builtin.file: path: /usr/local/sbin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74348,27 +85905,52 @@ ownership with the following command: $ sudo chown root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002521 - SV-271787r1092073_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002521 + SV-271787r1092073_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Proper ownership of library directories is necessary to protect the integrity of the system. - find -H /lib/ -type d -exec chown -L 0 {} \; -find -H /lib64/ -type d -exec chown -L 0 {} \; -find -H /usr/lib/ -type d -exec chown -L 0 {} \; -find -H /usr/lib64/ -type d -exec chown -L 0 {} \; + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /lib/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /lib64/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/lib/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/lib64/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi - - name: Ensure owner on directory /lib/ recursively - file: + - name: Set the dir_ownership_library_dirs_newown variable if represented by uid + ansible.builtin.set_fact: + dir_ownership_library_dirs_newown: '0' + tags: + - DISA-STIG-OL09-00-002521 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /lib/ recursively + ansible.builtin.file: path: /lib/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74381,11 +85963,12 @@ find -H /usr/lib64/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /lib64/ recursively - file: + ansible.builtin.file: path: /lib64/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74398,11 +85981,12 @@ find -H /usr/lib64/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/lib/ recursively - file: + ansible.builtin.file: path: /usr/lib/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74415,11 +85999,12 @@ find -H /usr/lib64/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/lib64/ recursively - file: + ansible.builtin.file: path: /usr/lib64/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74454,8 +86039,7 @@ following command: $ sudo chmod go-w DIR - CCI-001495 - SRG-OS-000258-GPOS-00099 + SRG-OS-000258-GPOS-00099 System binaries are executed by privileged users, as well as system services, and restrictive permissions are necessary to ensure execution of these programs cannot be co-opted. @@ -74476,7 +86060,7 @@ find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - name: Find /bin/ file(s) recursively - command: 'find -H /bin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /bin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74490,7 +86074,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /bin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74505,7 +86089,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /sbin/ file(s) recursively - command: 'find -H /sbin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /sbin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74519,7 +86103,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /sbin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74534,7 +86118,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/bin/ file(s) recursively - command: 'find -H /usr/bin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/bin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74548,7 +86132,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/bin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74563,7 +86147,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/sbin/ file(s) recursively - command: 'find -H /usr/sbin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/sbin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74577,7 +86161,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/sbin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74592,7 +86176,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/local/bin/ file(s) recursively - command: 'find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74606,7 +86190,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/local/bin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74621,7 +86205,8 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/local/sbin/ file(s) recursively - command: 'find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -74635,7 +86220,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/local/sbin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74674,14 +86259,13 @@ its permission with the following command: $ sudo chmod go-w DIR - CCI-001499 - CIP-003-8 R6 + CIP-003-8 R6 CM-5 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002522 - SV-271788r1092076_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002522 + SV-271788r1092076_rule If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management process. @@ -74704,7 +86288,7 @@ find -H /usr/lib/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - name: Find /lib/ file(s) recursively - command: 'find -H /lib/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /lib/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74722,7 +86306,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74741,7 +86325,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Find /lib64/ file(s) recursively - command: 'find -H /lib64/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /lib64/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74759,7 +86343,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74778,7 +86362,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Find /usr/lib/ file(s) recursively - command: 'find -H /usr/lib/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /usr/lib/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74796,7 +86380,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /usr/lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74815,7 +86399,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Find /usr/lib64/ file(s) recursively - command: 'find -H /usr/lib64/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /usr/lib64/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74833,7 +86417,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /usr/lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74860,7 +86444,8 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; Verify Group Who Owns /etc/sysctl.d Directory - To properly set the group owner of /etc/sysctl.d, run the command: $ sudo chgrp root /etc/sysctl.d + To properly set the group owner of /etc/sysctl.d, run the command: +$ sudo chgrp root /etc/sysctl.d R50 The ownership of the /etc/sysctl.d directory by the root group is important @@ -74871,7 +86456,17 @@ ensures exclusive control of the kernel configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/sysctl.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/sysctl.d/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -74888,11 +86483,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - directory_groupowner_etc_sysctld_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_sysctld_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_sysctld_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/sysctl.d/ - file: + ansible.builtin.file: path: /etc/sysctl.d/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_sysctld_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -74911,7 +86537,8 @@ fi Verify User Who Owns /etc/sysctl.d Directory - To properly set the owner of /etc/sysctl.d, run the command: $ sudo chown root /etc/sysctl.d + To properly set the owner of /etc/sysctl.d, run the command: +$ sudo chown root /etc/sysctl.d R50 The ownership of the /etc/sysctl.d directory by the root user is important @@ -74922,7 +86549,17 @@ ensures exclusive control of the kernel configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/sysctl.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/sysctl.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -74939,11 +86576,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_sysctld_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_sysctld_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/sysctl.d/ - file: + ansible.builtin.file: path: /etc/sysctl.d/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_sysctld_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -74973,7 +86623,7 @@ ensures exclusive control of the kernel configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/sysctl.d/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; +find -H /etc/sysctl.d/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -74991,7 +86641,8 @@ fi - no_reboot_needed - name: Find /etc/sysctl.d/ file(s) - command: 'find -H /etc/sysctl.d/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /etc/sysctl.d/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -75006,7 +86657,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/sysctl.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -75046,13 +86697,12 @@ with the following command: $ sudo chgrp root FILE - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 - OL09-00-002504 - SV-271773r1092031_rule + OL09-00-002504 + SV-271773r1092031_rule If the operating system allows any user to make changes to software libraries, then those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management @@ -75064,13 +86714,16 @@ escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. -for SYSCMDFILES in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -do - find -L $SYSCMDFILES \! -group root -type f -exec chgrp root '{}' \; -done +find -P /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin \! -group root -type f -exec chgrp root '{}' \; || true - - name: Retrieve the system command files and set their group ownership to root - command: find -L {{ item }} ! -group root -type f -exec chgrp root '{}' \; + - name: Verify that system commands files are group owned by root or a system account + - Find system command files with incorrect group ownership + ansible.builtin.find: + paths: '{{ item }}' + file_type: file + follow: false + recurse: false + register: system_command_files_found with_items: - /bin - /sbin @@ -75079,8 +86732,24 @@ done - /usr/local/bin - /usr/local/sbin changed_when: false - failed_when: false - check_mode: false + tags: + - DISA-STIG-OL09-00-002504 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - file_groupownership_system_commands_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that system commands files are group owned by root or a system account + - Set group ownership to root for system command files + ansible.builtin.file: + path: '{{ item.path }}' + group: root + with_items: '{{ system_command_files_found.results | map(attribute=''files'') | + flatten | rejectattr(''gr_name'', ''equalto'', ''root'') | list }}' tags: - DISA-STIG-OL09-00-002504 - NIST-800-53-CM-5(6) @@ -75128,7 +86797,6 @@ following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75155,40 +86823,35 @@ following command: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-5(6) CM-5(6).1 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 - OL09-00-002505 - SV-271774r1092034_rule + 1409 + OL09-00-002505 + SV-271774r1092034_rule System binaries are executed by privileged users as well as system services, and restrictive permissions are necessary to ensure that their execution of these programs cannot be co-opted. - find /bin/ \ -/usr/bin/ \ -/usr/local/bin/ \ -/sbin/ \ -/usr/sbin/ \ -/usr/local/sbin/ \ -/usr/libexec \ -\! -user root -execdir chown root {} \; + +find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/ /usr/libexec \! -user root -execdir chown root {} \; - name: Read list of system executables without root ownership - command: find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/ - /usr/libexec \! -user root + ansible.builtin.command: find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ + /usr/local/sbin/ /usr/libexec \! -user root register: no_root_system_executables changed_when: false failed_when: false @@ -75207,7 +86870,7 @@ execution of these programs cannot be co-opted. - restrict_strategy - name: Set ownership to root of system executables - file: + ansible.builtin.file: path: '{{ item }}' owner: root with_items: '{{ no_root_system_executables.stdout_lines }}' @@ -75262,7 +86925,6 @@ ownership with the following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75289,38 +86951,67 @@ ownership with the following command: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-5(6) CM-5(6).1 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 - OL09-00-002524 - SV-271790r1092082_rule + SRG-OS-000259-GPOS-00100 + 1409 + OL09-00-002524 + SV-271790r1134866_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Proper ownership is necessary to protect the integrity of the system. -find /lib/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi -find /lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else -find /usr/lib/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +find -P /lib/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; -find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +find -P /lib64/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; + +find -P /usr/lib/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; + +find -P /usr/lib64/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; + +fi - - name: Find /lib/ file(s) matching ^.*$ recursively - command: find -H /lib/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" + - name: Set the file_ownership_library_dirs_newown variable if represented by uid + ansible.builtin.set_fact: + file_ownership_library_dirs_newown: '0' + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75338,10 +87029,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /lib/ file(s) matching ^.*$ - file: +- name: Ensure owner on /lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75358,8 +87050,9 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Find /lib64/ file(s) matching ^.*$ recursively - command: find -H /lib64/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" +- name: Find /lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib64/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75377,10 +87070,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /lib64/ file(s) matching ^.*$ - file: +- name: Ensure owner on /lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75397,8 +87091,9 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Find /usr/lib/ file(s) matching ^.*$ recursively - command: find -H /usr/lib/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" +- name: Find /usr/lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75416,10 +87111,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /usr/lib/ file(s) matching ^.*$ - file: +- name: Ensure owner on /usr/lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75436,9 +87132,9 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Find /usr/lib64/ file(s) matching ^.*$ recursively - command: find -H /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex - "^.*$" +- name: Find /usr/lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib64/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75456,10 +87152,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /usr/lib64/ file(s) matching ^.*$ - file: +- name: Ensure owner on /usr/lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75512,7 +87209,6 @@ following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75539,25 +87235,26 @@ following command: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-5(6) CM-5(6).1 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 - OL09-00-002506 - SV-271775r1092037_rule + 1409 + OL09-00-002506 + SV-271775r1092037_rule System binaries are executed by privileged users, as well as system services, and restrictive permissions are necessary to ensure execution of these programs cannot be co-opted. @@ -75567,8 +87264,8 @@ for dirPath in $DIRS; do done - name: Read list of world and group writable system executables - ansible.builtin.command: find /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin - /usr/libexec -perm /022 -type f + ansible.builtin.command: find -L /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin + /usr/libexec -perm /022 \( -type l -o -type f \) register: world_writable_library_files changed_when: false failed_when: false @@ -75643,7 +87340,6 @@ its permission with the following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75670,24 +87366,25 @@ its permission with the following command: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) CM-5(6) CM-5(6).1 AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 - OL09-00-002525 - SV-271791r1092085_rule + SRG-OS-000259-GPOS-00100 + 1409 + OL09-00-002525 + SV-271791r1134971_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Restrictive permissions are necessary to protect the integrity of the system. @@ -75695,17 +87392,17 @@ runtime. Restrictive permissions are necessary to protect the integrity of the s -find /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; -find /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; -find /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; -find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; - name: Find /lib/ file(s) recursively - command: find -H /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex - "^.*$" + ansible.builtin.command: find -P /lib/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75724,7 +87421,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75744,8 +87441,8 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Find /lib64/ file(s) recursively - command: find -H /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex - "^.*$" + ansible.builtin.command: find -P /lib64/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75764,7 +87461,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75784,8 +87481,8 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Find /usr/lib/ file(s) recursively - command: find -H /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex - "^.*$" + ansible.builtin.command: find -P /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75804,7 +87501,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /usr/lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75824,8 +87521,8 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Find /usr/lib64/ file(s) recursively - command: find -H /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended - -regex "^.*$" + ansible.builtin.command: find -P /usr/lib64/ -perm /g+w,o+w -type f -regextype + posix-extended -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75844,7 +87541,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /usr/lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75881,17 +87578,16 @@ by default: /usr/lib64 All system-wide shared library files should be protected from unauthorised -access. If any of these files is not group-owned by root, correct its group-owner with -the following command: +access. If any of these files is not group-owned by root, +correct its group-owner with the following command: $ sudo chgrp root FILE - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002523 - SV-271789r1092079_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002523 + SV-271789r1134863_rule If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management process. @@ -75902,16 +87598,39 @@ also include privileged programs which execute with escalated privileges. Only q and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. -find /lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi -find /lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; -find /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; - -find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; +fi - - name: Find /lib/ file(s) matching ^.*$ recursively - command: find -H /lib/ -type f ! -group 0 -regextype posix-extended -regex "^.*$" + - name: Set the root_permissions_syslibrary_files_newgroup variable if represented + by gid + ansible.builtin.set_fact: + root_permissions_syslibrary_files_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Find /lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75927,10 +87646,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /lib/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75945,8 +87665,9 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Find /lib64/ file(s) matching ^.*$ recursively - command: find -H /lib64/ -type f ! -group 0 -regextype posix-extended -regex "^.*$" +- name: Find /lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib64/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75962,10 +87683,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /lib64/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75980,9 +87702,9 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Find /usr/lib/ file(s) matching ^.*$ recursively - command: find -H /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex - "^.*$" +- name: Find /usr/lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75998,10 +87720,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /usr/lib/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /usr/lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -76016,9 +87739,9 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Find /usr/lib64/ file(s) matching ^.*$ recursively - command: find -H /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex - "^.*$" +- name: Find /usr/lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib64/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -76034,10 +87757,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /usr/lib64/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /usr/lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -76107,9 +87831,6 @@ The autofs service can be disabled with the following com DSS06.03 DSS06.10 3.4.6 - CCI-000778 - CCI-000366 - CCI-001958 164.308(a)(3)(i) 164.308(a)(3)(ii)(A) 164.310(d)(1) @@ -76166,11 +87887,11 @@ The autofs service can be disabled with the following com PR.AC-3 PR.AC-6 PR.AC-7 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - OL09-00-002000 - SV-271639r1091629_rule + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + OL09-00-002000 + SV-271639r1091629_rule Disabling the automounter permits the administrator to statically control filesystem mounting through /etc/fstab. @@ -76220,97 +87941,54 @@ fi - no_reboot_needed - service_autofs_disabled -- name: Disable the Automounter - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable the Automounter - Disable service autofs + block: + + - name: Disable the Automounter - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable the Automounter - Ensure autofs.service is Masked + ansible.builtin.systemd: + name: autofs.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("autofs.service", multiline=True) + + - name: Unit Socket Exists - autofs.socket + ansible.builtin.command: systemctl -q list-unit-files autofs.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable the Automounter - Disable Socket autofs + ansible.builtin.systemd: + name: autofs.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("autofs.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + - special_service_block when: ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Disable the Automounter - Ensure autofs.service is Masked - ansible.builtin.systemd: - name: autofs.service - state: stopped - enabled: false - masked: true - when: - - ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("autofs.service", multiline=True) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Unit Socket Exists - autofs.socket - ansible.builtin.command: systemctl -q list-unit-files autofs.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Disable the Automounter - Disable Socket autofs - ansible.builtin.systemd: - name: autofs.socket - enabled: false - state: stopped - masked: true - when: - - ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("autofs.socket", multiline=True) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled include disable_autofs @@ -76325,6 +88003,10 @@ class disable_autofs { [customizations.services] masked = ["autofs"] + + + + @@ -76338,6 +88020,11 @@ masked = ["autofs"] To configure the system to prevent the cramfs kernel module from being loaded, add the following line to the file /etc/modprobe.d/cramfs.conf: install cramfs /bin/false +This entry will cause a non-zero return value during a cramfs module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install cramfs /bin/true To configure the system to prevent the cramfs from being used, add the following line to file /etc/modprobe.d/cramfs.conf: @@ -76361,7 +88048,6 @@ decompress the image. DSS05.05 DSS06.06 3.4.6 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -76418,9 +88104,9 @@ decompress the image. CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000095-GPOS-00049 - OL09-00-000045 - SV-271448r1091056_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000045 + SV-271448r1091056_rule Removing support for unneeded filesystem types reduces the local attack surface of the server. @@ -76460,7 +88146,7 @@ fi - reboot_required - name: Ensure kernel module 'cramfs' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/cramfs.conf regexp: install\s+cramfs @@ -76480,7 +88166,7 @@ fi - reboot_required - name: Ensure kernel module 'cramfs' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/cramfs.conf regexp: ^blacklist cramfs$ @@ -76512,6 +88198,11 @@ fi To configure the system to prevent the squashfs kernel module from being loaded, add the following line to the file /etc/modprobe.d/squashfs.conf: install squashfs /bin/false +This entry will cause a non-zero return value during a squashfs module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install squashfs /bin/true To configure the system to prevent the squashfs from being used, add the following line to file /etc/modprobe.d/squashfs.conf: @@ -76630,7 +88321,7 @@ fi - reboot_required - name: Ensure kernel module 'squashfs' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/squashfs.conf regexp: install\s+squashfs @@ -76649,7 +88340,7 @@ fi - reboot_required - name: Ensure kernel module 'squashfs' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/squashfs.conf regexp: ^blacklist squashfs$ @@ -76677,6 +88368,11 @@ fi To configure the system to prevent the udf kernel module from being loaded, add the following line to the file /etc/modprobe.d/udf.conf: install udf /bin/false +This entry will cause a non-zero return value during a udf module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install udf /bin/true To configure the system to prevent the udf from being used, add the following line to file /etc/modprobe.d/udf.conf: @@ -76687,7 +88383,7 @@ This effectively prevents usage of this uncommon filesystem. The udf filesystem type is the universal disk format used to implement the ISO/IEC 13346 and ECMA-167 specifications. This is an open vendor filesystem type for data storage on a broad -range of media. This filesystem type is neccessary to support +range of media. This filesystem type is necessary to support writing DVDs and newer optical disc formats. 11 14 @@ -76796,7 +88492,7 @@ fi - reboot_required - name: Ensure kernel module 'udf' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/udf.conf regexp: install\s+udf @@ -76815,7 +88511,7 @@ fi - reboot_required - name: Ensure kernel module 'udf' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/udf.conf regexp: ^blacklist udf$ @@ -76845,6 +88541,11 @@ to prevent automatic loading of the USB storage driver. To configure the system to prevent the usb-storage kernel module from being loaded, add the following line to the file /etc/modprobe.d/usb-storage.conf: install usb-storage /bin/false +This entry will cause a non-zero return value during a usb-storage module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install usb-storage /bin/true To configure the system to prevent the usb-storage from being used, add the following line to file /etc/modprobe.d/usb-storage.conf: @@ -76868,9 +88569,6 @@ module, but will not prevent an administrator (or another program) from using th DSS06.03 DSS06.10 3.1.21 - CCI-000778 - CCI-001958 - CCI-003959 164.308(a)(3)(i) 164.308(a)(3)(ii)(A) 164.310(d)(1) @@ -76927,17 +88625,15 @@ module, but will not prevent an administrator (or another program) from using th PR.AC-3 PR.AC-6 PR.AC-7 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - SRG-APP-000141-CTR-000315 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + SRG-APP-000141-CTR-000315 A.15.SEC-OL1 3.4.2 3.4 - OL09-00-000047 - OL09-00-002332 - SV-271450r1092466_rule - SV-271702r1091818_rule + OL09-00-000047 + SV-271450r1092466_rule USB storage devices such as thumb drives can be used to introduce malicious software. @@ -76965,7 +88661,6 @@ fi manager: auto tags: - DISA-STIG-OL09-00-000047 - - DISA-STIG-OL09-00-002332 - NIST-800-171-3.1.21 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -76981,7 +88676,7 @@ fi - reboot_required - name: Ensure kernel module 'usb-storage' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/usb-storage.conf regexp: install\s+usb-storage @@ -76989,7 +88684,6 @@ fi when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000047 - - DISA-STIG-OL09-00-002332 - NIST-800-171-3.1.21 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -77005,7 +88699,7 @@ fi - reboot_required - name: Ensure kernel module 'usb-storage' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/usb-storage.conf regexp: ^blacklist usb-storage$ @@ -77013,7 +88707,6 @@ fi when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000047 - - DISA-STIG-OL09-00-002332 - NIST-800-171-3.1.21 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -77043,6 +88736,23 @@ that limit what files on those partitions can do. These options are set in the /etc/fstab configuration file, and can be used to make certain types of malicious behavior more difficult. + + Value for hidepid option + The hidepid mount option is applicable to /proc and is used to control who can access +the information in /proc/[pid] directories. The option can have one of the following +values: +0: Everybody may access all /proc/[pid] directories. +1: Users may not access files and subdirectories inside any /proc/[pid] directories + but their own. The /proc/[pid] directories themselves remain visible. +2: Same as for mode 1, but in addition the /proc/[pid] directories belonging to other + users become invisible. + 0 + noaccess + invisible + 1 + 2 + 2 + Removable Partition This value is used by the checks mount_option_nodev_removable_partitions, mount_option_nodev_removable_partitions, @@ -77060,17 +88770,16 @@ should not be required on the boot partition. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /boot/efi. - CCI-000366 - CCI-001764 CM-6(b) CM-6.1(iv) - SRG-OS-000480-GPOS-00227 - OL09-00-002032 - SV-271649r1091659_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002032 + SV-271649r1091659_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from boot partitions. + # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/boot/efi" > /dev/null || findmnt --fstab "/boot/efi" > /dev/null; }; then function perform_remediation { @@ -77139,10 +88848,13 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false - when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + check_mode: false + when: + - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002032 - NIST-800-53-CM-6(b) @@ -77163,8 +88875,9 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77194,8 +88907,9 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77218,8 +88932,9 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: - DISA-STIG-OL09-00-002032 @@ -77242,8 +88957,9 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77275,16 +88991,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /boot. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -77294,13 +89009,13 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002030 - SV-271647r1091653_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002030 + SV-271647r1091653_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -77373,10 +89088,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002030 - NIST-800-53-AC-6 @@ -77401,8 +89117,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77435,8 +89151,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77463,8 +89179,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nodev" not in mount_info.options tags: - DISA-STIG-OL09-00-002030 @@ -77491,8 +89207,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77533,7 +89249,7 @@ Add the noexec option to the fourth column of binaries should be executed from this partition after the booting process finishes. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -77599,10 +89315,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - configure_strategy - high_disruption @@ -77620,8 +89337,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77647,8 +89364,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77668,8 +89385,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "noexec" not in mount_info.options tags: - configure_strategy @@ -77689,8 +89406,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77720,17 +89437,15 @@ should not be required on the boot partition. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /boot. - CCI-000366 - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -77740,15 +89455,15 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002031 - SV-271648r1091656_rule + OL09-00-002031 + SV-271648r1091656_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from boot partitions. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -77821,10 +89536,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002031 - NIST-800-53-AC-6 @@ -77849,8 +89565,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77883,8 +89599,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77911,8 +89627,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nosuid" not in mount_info.options tags: - DISA-STIG-OL09-00-002031 @@ -77939,8 +89655,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77992,7 +89708,6 @@ Add the nodev option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -78050,15 +89765,15 @@ Add the nodev option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -78068,13 +89783,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002040 - SV-271650r1091662_rule + SRG-OS-000368-GPOS-00154 + 1409 + OL09-00-002040 + SV-271650r1091662_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -78138,10 +89854,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002040 - NIST-800-53-AC-6 @@ -78166,8 +89883,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -78200,8 +89917,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -78228,8 +89945,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nodev" not in mount_info.options tags: - DISA-STIG-OL09-00-002040 @@ -78256,8 +89973,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | length == 0) @@ -78307,7 +90024,6 @@ Add the noexec option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -78365,15 +90081,15 @@ Add the noexec option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -78383,13 +90099,14 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002041 - SV-271651r1091665_rule + SRG-OS-000368-GPOS-00154 + 1409 + OL09-00-002041 + SV-271651r1091665_rule Allowing users to execute binaries from world-writable directories such as /dev/shm can expose the system to potential compromise. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -78453,10 +90170,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002041 - NIST-800-53-AC-6 @@ -78481,8 +90199,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -78516,8 +90234,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -78544,8 +90262,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "noexec" not in mount_info.options tags: - DISA-STIG-OL09-00-002041 @@ -78572,8 +90290,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | length == 0) @@ -78622,7 +90340,6 @@ Add the nosuid option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -78680,15 +90397,15 @@ Add the nosuid option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -78698,13 +90415,14 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002042 - SV-271652r1094966_rule + SRG-OS-000368-GPOS-00154 + 1409 + OL09-00-002042 + SV-271652r1094966_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -78768,10 +90486,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002042 - NIST-800-53-AC-6 @@ -78796,8 +90515,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -78831,8 +90550,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -78859,8 +90578,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nosuid" not in mount_info.options tags: - DISA-STIG-OL09-00-002042 @@ -78887,8 +90606,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | length == 0) @@ -78939,7 +90658,7 @@ single user or group can cause for other users (or the wider system) by intentio accidentally filling up the partition. Quotas can also be applied to inodes for filesystems where inode exhaustion is a concern. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -79019,8 +90738,8 @@ fi fstab_mount_point_info: [] when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79035,8 +90754,8 @@ fi database: passwd when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79052,8 +90771,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -79073,8 +90792,8 @@ fi filter: ansible_mounts when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79112,7 +90831,7 @@ fi - name: Add grpquota Option to /home - Ensure mount option grpquota is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},grpquota' @@ -79125,8 +90844,8 @@ fi - '''grpquota'' not in item.options' when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79153,30 +90872,27 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /home. - CCI-001764 - SRG-OS-000368-GPOS-00154 - OL09-00-002070 - SV-271666r1091710_rule + OVAL looks for partitions whose mount point is a substring of any interactive user's home +directory and validates that nodev option is there. Because of this, there could be false +negatives when several partitions share a base substring. For example, if there is a home +directory in /var/tmp/user1 and there are partitions mounted in /var and +/var/tmp. The nodev option is only expected in /var/tmp, but OVAL will +check both. +Bash remediation uses the df command to find out the partition where the home +directory is mounted. However, if the directory doesn't exist the remediation won't be +applied. + SRG-OS-000368-GPOS-00154 + OL09-00-002070 + SV-271666r1091710_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null; }; then -function perform_remediation { - - # the mount point /home has to be defined in /etc/fstab - # before this remediation can be executed. In case it is not defined, the - # remediation aborts and no changes regarding the mount point are done. - mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/home")" +function perform_remediation (){ - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /home)" + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $1)" # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab if ! grep -q "$mount_point_match_regexp" /etc/fstab; then @@ -79190,22 +90906,34 @@ function perform_remediation { if [ "$fs_type" == "iso9660" ] ; then previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") fi - echo " /home defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + echo " $1 defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab fi - - if mkdir -p "/home"; then - if mountpoint -q "/home"; then - mount -o remount --target "/home" + if mkdir -p "$1"; then + if mountpoint -q "$1"; then + mount -o remount --target "$1" fi fi } -perform_remediation +readarray -t home_directories < \ + <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) + + +for home_directory in "${home_directories[@]}" +do + if [ -d $home_directory ]; then + fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') + if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point + then + perform_remediation "$fstab_mount_point" + fi + fi +done else >&2 echo 'Remediation is not applicable, nothing was done' @@ -79223,16 +90951,26 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Check information associated to mountpoint' - command: findmnt --fstab '/home' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false +- name: Add nodev Option to /home - Initialize variables + ansible.builtin.set_fact: + non_allowed_partitions: + - / + - /lib + - /opt + - /usr + - /bin + - /sbin + - /boot + - /dev + - /proc + home_directories: [] + allowed_mount_point: [] + fstab_mount_point_info: [] when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002070 @@ -79243,20 +90981,15 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' +- name: Add nodev Option to /home - Get home directories from passwd + ansible.builtin.getent: + database: passwd when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79266,27 +90999,20 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: If /home not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /home - - '' - - '' - - defaults +- name: Add nodev Option to /home - Filter home directories based on UID range + ansible.builtin.set_fact: + home_directories: '{{ home_directories + [item.data[4]] }}' when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - ("--fstab" | length == 0) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length == 0) + - item.data[4] is defined + - item.data[2]|int >= 1000 + - item.data[2]|int != 65534 + - item.data[4] not in non_allowed_partitions + with_items: '{{ ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79296,18 +91022,15 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Make sure nodev option is part of the to /home - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' +- name: Add nodev Option to /home - Gather mount points + ansible.builtin.setup: + filter: ansible_mounts when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - mount_info is defined and "nodev" not in mount_info.options tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79317,22 +91040,51 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Ensure /home is mounted with nodev option' - mount: - path: /home - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' +- name: Add nodev Option to /home - Ensure mount options for home directories + block: + + - name: ' Add nodev Option to /home - Obtain mount point using df and shell' + ansible.builtin.shell: | + df {{ item }} | awk '/^\/dev/ {print $6}' + register: df_output + with_items: '{{ home_directories }}' + + - name: Add nodev Option to /home - Set mount point for each home directory + ansible.builtin.set_fact: + allowed_mount_point: '{{ allowed_mount_point + [item.stdout_lines[0]] }}' + with_items: '{{ df_output.results }}' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + - item.stdout_lines[0] != "" + + - name: Add nodev Option to /home - Obtain full mount information for allowed mount + point + ansible.builtin.set_fact: + fstab_mount_point_info: '{{ fstab_mount_point_info + [ ansible_mounts | selectattr(''mount'', + ''equalto'', item) | first ]}}' + with_items: '{{ allowed_mount_point }}' + when: allowed_mount_point is defined + + - name: Add nodev Option to /home - Ensure mount option nodev is in fstab for allowed + mount point + ansible.posix.mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},nodev' + state: mounted + fstype: '{{ item.fstype }}' + with_items: '{{ fstab_mount_point_info }}' + when: + - allowed_mount_point is defined + - item.mount not in non_allowed_partitions + - '''nodev'' not in item.options' when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - mount_info is defined - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79341,9 +91093,6 @@ fi - mount_option_home_nodev - no_reboot_needed - unknown_severity - - -part /home --mountoptions="nodev" @@ -79368,17 +91117,16 @@ check both. Bash remediation uses the df command to find out the partition where the home directory is mounted. However, if the directory doesn't exist the remediation won't be applied. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002072 - SV-271668r1091716_rule + OL09-00-002072 + SV-271668r1091716_rule The /home directory contains data of individual users. Binaries in this directory should not be considered as trusted and users should not be able to execute them. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -79459,8 +91207,8 @@ fi fstab_mount_point_info: [] when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79476,8 +91224,8 @@ fi database: passwd when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79494,8 +91242,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -79516,8 +91264,8 @@ fi filter: ansible_mounts when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79556,7 +91304,7 @@ fi - name: Add noexec Option to /home - Ensure mount option noexec is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},noexec' @@ -79569,8 +91317,8 @@ fi - '''noexec'' not in item.options' when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79620,8 +91368,6 @@ applied. DSS05.05 DSS05.06 DSS06.06 - CCI-000366 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -79679,15 +91425,15 @@ applied. A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -79697,15 +91443,15 @@ applied. PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002071 - SV-271667r1091713_rule + OL09-00-002071 + SV-271667r1091713_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from user home directory partitions. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -79791,8 +91537,8 @@ fi fstab_mount_point_info: [] when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79813,8 +91559,8 @@ fi database: passwd when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79836,8 +91582,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -79863,8 +91609,8 @@ fi filter: ansible_mounts when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79908,7 +91654,7 @@ fi - name: Add nosuid Option to /home - Ensure mount option nosuid is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},nosuid' @@ -79921,8 +91667,8 @@ fi - '''nosuid'' not in item.options' when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79970,7 +91716,7 @@ single user or group can cause for other users (or the wider system) by intentio accidentally filling up the partition. Quotas can also be applied to inodes for filesystems where inode exhaustion is a concern. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -80050,8 +91796,8 @@ fi fstab_mount_point_info: [] when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80066,8 +91812,8 @@ fi database: passwd when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80083,8 +91829,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -80104,8 +91850,8 @@ fi filter: ansible_mounts when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80143,7 +91889,7 @@ fi - name: Add usrquota Option to /home - Ensure mount option usrquota is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},usrquota' @@ -80156,8 +91902,8 @@ fi - '''usrquota'' not in item.options' when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80195,7 +91941,6 @@ Add the nodev option to the fourth column of DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -80247,15 +91992,15 @@ Add the nodev option to the fourth column of A.14.2.3 A.14.2.4 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -80264,18 +92009,18 @@ Add the nodev option to the fourth column of MP-7 PR.IP-1 PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002080 - SV-271669r1091719_rule + OL09-00-002080 + SV-271669r1091719_rule The nodev mount option prevents files from being interpreted as character or block devices. The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails, for which it is not advised to set nodev on these filesystems. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then MOUNT_OPTION="nodev" # Create array of local non-root partitions @@ -80285,38 +92030,73 @@ readarray -t partitions_records < <(findmnt --mtab --raw --evaluate | grep readarray -t polyinstantiated_dirs < \ <(grep -oP "^\s*[^#\s]+\s+\S+" /etc/security/namespace.conf | grep -oP "(?<=\s)\S+?(?=/?\$)") +# Define excluded non-local file systems +excluded_fstypes=( + afs + autofs + ceph + cifs + smb3 + smbfs + sshfs + ncpfs + ncp + nfs + nfs4 + gfs + gfs2 + glusterfs + gpfs + pvfs2 + ocfs2 + lustre + davfs + fuse.sshfs +) for partition_record in "${partitions_records[@]}"; do # Get all important information for fstab - mount_point="$(echo ${partition_record} | cut -d " " -f1)" - device="$(echo ${partition_record} | cut -d " " -f2)" - device_type="$(echo ${partition_record} | cut -d " " -f3)" - if ! printf '%s\0' "${polyinstantiated_dirs[@]}" | grep -qxzF "$mount_point"; then - # device and device_type will be used only in case when the device doesn't have fstab record - mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $mount_point)" + mount_point="$(echo "${partition_record}" | cut -d " " -f1)" + device="$(echo "${partition_record}" | cut -d " " -f2)" + device_type="$(echo "${partition_record}" | cut -d " " -f3)" - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep -q "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|$MOUNT_OPTION)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="$device_type" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "$MOUNT_OPTION"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,$MOUNT_OPTION|" /etc/fstab + # Skip polyinstantiated directories + if printf '%s\0' "${polyinstantiated_dirs[@]}" | grep -qxzF "$mount_point"; then + continue + fi + + # Skip any non-local filesystem + for excluded_fstype in "${excluded_fstypes[@]}"; do + if [[ "$device_type" == "$excluded_fstype" ]]; then + # jump out of both loops and move to next partition_record + continue 2 fi - if mkdir -p "$mount_point"; then - if mountpoint -q "$mount_point"; then - mount -o remount --target "$mount_point" - fi + done + + # If we reach here, it's a local, non-root partition that isn't excluded. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $mount_point)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|$MOUNT_OPTION)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="$device_type" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "$MOUNT_OPTION"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,$MOUNT_OPTION|" /etc/fstab + fi + if mkdir -p "$mount_point"; then + if mountpoint -q "$mount_point"; then + mount -o remount --target "$mount_point" fi fi done @@ -80347,12 +92127,55 @@ fi - no_reboot_needed - name: 'Add nodev Option to Non-Root Local Partitions: Refresh facts' - setup: + ansible.builtin.setup: gather_subset: mounts when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + tags: + - DISA-STIG-OL09-00-002080 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_nonroot_local_partitions + - no_reboot_needed + +- name: 'Add nodev Option to Non-Root Local Partitions: Define excluded (non-local) + file systems' + ansible.builtin.set_fact: + excluded_fstypes: + - afs + - autofs + - ceph + - cifs + - smb3 + - smbfs + - sshfs + - ncpfs + - ncp + - nfs + - nfs4 + - gfs + - gfs2 + - glusterfs + - gpfs + - pvfs2 + - ocfs2 + - lustre + - davfs + - fuse.sshfs + when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002080 - NIST-800-53-AC-6 @@ -80370,7 +92193,7 @@ fi - name: 'Add nodev Option to Non-Root Local Partitions: Ensure non-root local partitions are mounted with nodev option' - mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},nodev' @@ -80379,10 +92202,11 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.mount is match('/\w') - item.options is not search('nodev') + - item.fstype not in excluded_fstypes with_items: - '{{ ansible_facts.mounts }}' tags: @@ -80404,12 +92228,12 @@ fi are present with nodev option in /etc/fstab' ansible.builtin.replace: path: /etc/fstab - regexp: ^\s*(?!#)(/dev/\S+|UUID=\S+)\s+(/\w\S*)\s+(\S+)\s+(?!nodev)(\S+)(.*)$ + regexp: ^\s*(?!#)(/dev/\S+|UUID=\S+)\s+(/\w\S*)\s+(\S+)\s+(?!.*\bnodev\b)(\S+)(.*)$ replace: \1 \2 \3 \4,nodev \5 when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002080 - NIST-800-53-AC-6 @@ -80465,7 +92289,6 @@ Add the nodev option to the fourth column of DSS05.07 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -80531,15 +92354,15 @@ Add the nodev option to the fourth column of A.8.3.3 A.9.1.2 A.9.2.1 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -80551,15 +92374,15 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002021 - SV-271645r1091647_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002021 + SV-271645r1091647_rule The only legitimate location for device files is the /dev directory located on the root partition. An exception to this is chroot jails, and it is not advised to set nodev on partitions which contain their root filesystems. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then var_removable_partition='' @@ -80602,15 +92425,15 @@ fi - always - name: Ensure permission nodev are set on var_removable_partition - lineinfile: + ansible.builtin.lineinfile: path: /etc/fstab regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ backrefs: true line: \1 \2 \3 \4,nodev \5 when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002021 - NIST-800-53-AC-6 @@ -80666,7 +92489,6 @@ Add the noexec option to the fourth column of DSS05.07 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -80732,15 +92554,15 @@ Add the noexec option to the fourth column of A.8.3.3 A.9.1.2 A.9.2.1 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -80752,13 +92574,13 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002020 - SV-271644r1091644_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002020 + SV-271644r1091644_rule Allowing users to execute binaries from removable media such as USB keys exposes the system to potential compromise. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then var_removable_partition='' @@ -80801,15 +92623,15 @@ fi - always - name: Ensure permission noexec are set on var_removable_partition - lineinfile: + ansible.builtin.lineinfile: path: /etc/fstab regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ backrefs: true line: \1 \2 \3 \4,noexec \5 when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002020 - NIST-800-53-AC-6 @@ -80839,7 +92661,7 @@ fi and set-group-identifier (SGID) permissions from taking effect. These permissions allow users to execute binaries with the same permissions as the owner and group of the file respectively. Users should not be allowed to introduce SUID and SGID -files into the system via partitions mounted from removeable media. +files into the system via partitions mounted from removable media. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of @@ -80871,7 +92693,6 @@ Add the nosuid option to the fourth column of DSS06.02 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -80955,15 +92776,15 @@ Add the nosuid option to the fourth column of A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -80977,14 +92798,14 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002022 - SV-271646r1091650_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002022 + SV-271646r1091650_rule The presence of SUID and SGID executables should be tightly controlled. Allowing users to introduce SUID or SGID binaries from partitions mounted off of removable media would allow them to introduce their own highly-privileged programs. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then var_removable_partition='' @@ -81027,15 +92848,15 @@ fi - always - name: Ensure permission nosuid are set on var_removable_partition - lineinfile: + ansible.builtin.lineinfile: path: /etc/fstab regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ backrefs: true line: \1 \2 \3 \4,nosuid \5 when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002022 - NIST-800-53-AC-6 @@ -81073,7 +92894,7 @@ Add the nosuid option to the fourth column of not be able to execute SUID or SGID binaries from this directory. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/opt" > /dev/null || findmnt --fstab "/opt" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/opt" > /dev/null || findmnt --fstab "/opt" > /dev/null; }; then function perform_remediation { @@ -81139,11 +92960,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -81162,8 +92984,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -81190,8 +93012,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -81212,8 +93034,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -81234,8 +93056,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -81272,7 +93094,7 @@ Add the nosuid option to the fourth column of not be able to execute SUID or SGID binaries from this directory. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/srv" > /dev/null || findmnt --fstab "/srv" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/srv" > /dev/null || findmnt --fstab "/srv" > /dev/null; }; then function perform_remediation { @@ -81338,11 +93160,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -81361,8 +93184,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -81389,8 +93212,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -81411,8 +93234,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -81433,8 +93256,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -81480,7 +93303,6 @@ Add the nodev option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -81538,15 +93360,15 @@ Add the nodev option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -81556,14 +93378,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002050 - SV-271653r1091671_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002050 + SV-271653r1091671_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then function perform_remediation { @@ -81636,11 +93458,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002050 @@ -81666,8 +93489,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -81701,8 +93524,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -81729,8 +93552,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -81758,8 +93581,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -81811,7 +93634,6 @@ Add the noexec option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -81869,15 +93691,15 @@ Add the noexec option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -81887,16 +93709,16 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002051 - SV-271654r1091674_rule + OL09-00-002051 + SV-271654r1091674_rule Allowing users to execute binaries from world-writable directories such as /tmp should never be necessary in normal operation and can expose the system to potential compromise. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then function perform_remediation { @@ -81969,11 +93791,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002051 @@ -81999,8 +93822,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82034,8 +93857,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82063,8 +93886,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -82092,8 +93915,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82146,7 +93969,6 @@ Add the nosuid option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -82204,15 +94026,15 @@ Add the nosuid option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -82222,15 +94044,15 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002052 - SV-271655r1091677_rule + OL09-00-002052 + SV-271655r1091677_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then function perform_remediation { @@ -82303,11 +94125,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002052 @@ -82333,8 +94156,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82368,8 +94191,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82397,8 +94220,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -82426,8 +94249,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82467,16 +94290,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -82487,14 +94309,14 @@ Add the nodev option to the fourth column of PR.PT-2 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000368-GPOS-00154 - OL09-00-002064 - SV-271660r1091692_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002064 + SV-271660r1091692_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then function perform_remediation { @@ -82567,11 +94389,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002064 @@ -82597,8 +94420,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82633,8 +94456,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82662,8 +94485,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -82692,8 +94515,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82730,16 +94553,15 @@ from being executed out of /var/log/audit. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -82750,15 +94572,15 @@ Add the noexec option to the fourth column of PR.PT-2 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000368-GPOS-00154 - OL09-00-002065 - SV-271661r1091695_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002065 + SV-271661r1091695_rule Allowing users to execute binaries from directories containing audit log files such as /var/log/audit should never be necessary in normal operation and can expose the system to potential compromise. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then function perform_remediation { @@ -82831,11 +94653,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002065 @@ -82861,8 +94684,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82897,8 +94720,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82926,8 +94749,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -82956,8 +94779,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82995,16 +94818,15 @@ should not be required in directories containing audit log files. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -83015,15 +94837,15 @@ Add the nosuid option to the fourth column of PR.PT-2 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000368-GPOS-00154 - OL09-00-002066 - SV-271662r1091698_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002066 + SV-271662r1091698_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for audit log files. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then function perform_remediation { @@ -83096,11 +94918,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002066 @@ -83126,8 +94949,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83162,8 +94985,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83191,8 +95014,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -83221,8 +95044,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -83262,16 +95085,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/log. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -83281,14 +95103,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002061 - SV-271657r1091683_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002061 + SV-271657r1091683_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then function perform_remediation { @@ -83361,11 +95183,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002061 @@ -83391,8 +95214,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83426,8 +95249,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83455,8 +95278,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -83484,8 +95307,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -83522,16 +95345,15 @@ from being executed out of /var/log. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/log. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -83541,16 +95363,16 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002062 - SV-271658r1091686_rule + OL09-00-002062 + SV-271658r1091686_rule Allowing users to execute binaries from directories containing log files such as /var/log should never be necessary in normal operation and can expose the system to potential compromise. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then function perform_remediation { @@ -83623,11 +95445,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002062 @@ -83653,8 +95476,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83689,8 +95512,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83718,8 +95541,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -83747,8 +95570,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -83786,16 +95609,15 @@ should not be required in directories containing log files. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/log. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -83805,16 +95627,16 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002063 - SV-271659r1091689_rule + OL09-00-002063 + SV-271659r1091689_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for log files. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then function perform_remediation { @@ -83887,11 +95709,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002063 @@ -83917,8 +95740,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83953,8 +95776,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83982,8 +95805,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -84011,8 +95834,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84052,16 +95875,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var. - CCI-001764 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -84071,14 +95893,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002060 - SV-271656r1091680_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002060 + SV-271656r1091680_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then function perform_remediation { @@ -84151,11 +95973,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002060 @@ -84181,8 +96004,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84216,8 +96039,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84244,8 +96067,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -84273,8 +96096,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84316,7 +96139,7 @@ Add the noexec option to the fourth column of mails and caches. No binaries should be executed from this directory. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then function perform_remediation { @@ -84382,11 +96205,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -84405,8 +96229,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84433,8 +96257,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84455,8 +96279,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -84477,8 +96301,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84513,7 +96337,7 @@ Add the nosuid option to the fourth column of The presence of SUID and SGID executables should be tightly controlled. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then function perform_remediation { @@ -84579,11 +96403,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -84602,8 +96427,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84630,8 +96455,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84652,8 +96477,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -84674,8 +96499,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84706,15 +96531,14 @@ should not exist within temporary directories like /var/tmpnodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp. - CCI-001764 - SRG-OS-000368-GPOS-00154 - OL09-00-002067 - SV-271663r1091701_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002067 + SV-271663r1091701_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then function perform_remediation { @@ -84781,11 +96605,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002067 @@ -84805,8 +96630,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84834,8 +96659,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84857,8 +96682,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -84880,8 +96705,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84912,17 +96737,16 @@ from being executed out of /var/tmp. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp. - CCI-001764 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002068 - SV-271664r1091704_rule + OL09-00-002068 + SV-271664r1091704_rule Allowing users to execute binaries from world-writable directories such as /var/tmp should never be necessary in normal operation and can expose the system to potential compromise. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then function perform_remediation { @@ -84989,11 +96813,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002068 @@ -85013,8 +96838,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -85043,8 +96868,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -85066,8 +96891,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -85089,8 +96914,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -85122,16 +96947,15 @@ should not be required in these world-writable directories. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp. - CCI-001764 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002069 - SV-271665r1091707_rule + OL09-00-002069 + SV-271665r1091707_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions. # Remediation is applicable only in certain platforms -if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then +if ( ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then function perform_remediation { @@ -85198,11 +97022,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002069 @@ -85222,8 +97047,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -85252,8 +97077,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -85275,8 +97100,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -85298,8 +97123,8 @@ fi when: - ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages - ) and not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -85342,11 +97167,10 @@ or compromised programs. Disable the uvcvideo module If the device contains a camera it should be covered or disabled when not in use. - CCI-000381 CM-7 (a) CM-7 (5) (b) - SRG-OS-000095-GPOS-00049 - SRG-OS-000370-GPOS-00155 + SRG-OS-000095-GPOS-00049 + SRG-OS-000370-GPOS-00155 Failing to disconnect from collaborative computing devices (i.e., cameras) can result in subsequent compromises of organizational information. Providing easy methods to physically disconnect from such devices after a collaborative computing session helps to ensure participants actually carry out the disconnect activity without having to go through complex and tedious procedures. @@ -85383,7 +97207,7 @@ fi - reboot_required - name: Ensure kernel module 'uvcvideo' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/uvcvideo.conf regexp: install\s+uvcvideo @@ -85400,7 +97224,7 @@ fi - reboot_required - name: Ensure kernel module 'uvcvideo' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/uvcvideo.conf regexp: ^blacklist uvcvideo$ @@ -85428,14 +97252,13 @@ fi To set the runtime status of the kernel.core_pattern kernel parameter, run the following command: $ sudo sysctl -w kernel.core_pattern=|/bin/false To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.core_pattern = |/bin/false - CCI-000366 SC-7(10) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002380 - SV-271728r1091896_rule + OL09-00-002380 + SV-271728r1091896_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems. @@ -85471,7 +97294,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.core_pattern # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.core_pattern="|/bin/false" fi @@ -85520,16 +97343,12 @@ fi - reboot_required - sysctl_kernel_core_pattern -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable storing core dumps - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.core_pattern.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002380 @@ -85544,13 +97363,62 @@ fi - reboot_required - sysctl_kernel_core_pattern -- name: Comment out any occurrences of kernel.core_pattern from config files - replace: - path: '{{ item.path }}' +- name: Disable storing core dumps - Find all files that contain kernel.core_pattern + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_pattern\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: Disable storing core dumps - Find all files that set kernel.core_pattern to + correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_pattern\s*=\s*\|/bin/false$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: Disable storing core dumps - Comment out any occurrences of kernel.core_pattern + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.core_pattern replace: '#kernel.core_pattern' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002380 - NIST-800-53-SC-7(10) @@ -85564,8 +97432,8 @@ fi - reboot_required - sysctl_kernel_core_pattern -- name: Ensure sysctl kernel.core_pattern is set to |/bin/false - sysctl: +- name: Disable storing core dumps - Ensure sysctl kernel.core_pattern is set to |/bin/false + ansible.posix.sysctl: name: kernel.core_pattern value: '|/bin/false' sysctl_file: /etc/sysctl.conf @@ -85585,6 +97453,10 @@ fi - reboot_required - sysctl_kernel_core_pattern + + + + @@ -85682,15 +97554,14 @@ fi - reboot_required - sysctl_kernel_core_pattern_empty_string -- name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - contains: ^[\s]*kernel.core_pattern.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d +- name: Disable storing core dumps - Find all files that contain kernel.core_pattern + ansible.builtin.shell: + cmd: find -L /etc/sysctl.conf /etc/sysctl.d/ /run/sysctl.d/ -type f -name '*.conf' + | xargs grep -HP '^\s*kernel.core_pattern\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -85700,14 +97571,35 @@ fi - reboot_required - sysctl_kernel_core_pattern_empty_string -- name: Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf - files - replace: - path: '{{ item.path }}' +- name: Disable storing core dumps - Find all files that set kernel.core_pattern to + correct value + ansible.builtin.shell: + cmd: find -L /etc/sysctl.conf /etc/sysctl.d/ /run/sysctl.d/ -type f -name '*.conf' + | xargs grep -HP '^\s*kernel.core_pattern\s*=\s*$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + +- name: Disable storing core dumps - Comment out any occurrences of kernel.core_pattern + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.core_pattern replace: '#kernel.core_pattern' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -85716,25 +97608,11 @@ fi - reboot_required - sysctl_kernel_core_pattern_empty_string -- name: Comment out any occurrences of kernel.core_pattern with value from /etc/sysctl.conf - files - replace: - path: /etc/sysctl.conf - regexp: ^[\s]*kernel.core_pattern([ \t]*=[ \t]*\S+) - replace: '#kernel.core_pattern\1' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_pattern_empty_string - -- name: Ensure sysctl kernel.core_pattern is set to empty - sysctl: +- name: Disable storing core dumps - Ensure sysctl kernel.core_pattern is set to empty + ansible.posix.sysctl: name: kernel.core_pattern value: ' ' + sysctl_file: /etc/sysctl.conf state: present reload: true when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -85799,7 +97677,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.core_uses_pid # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.core_uses_pid="0" fi @@ -85843,16 +97721,12 @@ fi - reboot_required - sysctl_kernel_core_uses_pid -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Configure file name of core dumps - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.core_uses_pid.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -85862,13 +97736,52 @@ fi - reboot_required - sysctl_kernel_core_uses_pid -- name: Comment out any occurrences of kernel.core_uses_pid from config files - replace: - path: '{{ item.path }}' +- name: Configure file name of core dumps - Find all files that contain kernel.core_uses_pid + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_uses_pid\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: Configure file name of core dumps - Find all files that set kernel.core_uses_pid + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_uses_pid\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: Configure file name of core dumps - Comment out any occurrences of kernel.core_uses_pid + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.core_uses_pid replace: '#kernel.core_uses_pid' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -85877,8 +97790,9 @@ fi - reboot_required - sysctl_kernel_core_uses_pid -- name: Ensure sysctl kernel.core_uses_pid is set to 0 - sysctl: +- name: Configure file name of core dumps - Ensure sysctl kernel.core_uses_pid is + set to 0 + ansible.posix.sysctl: name: kernel.core_uses_pid value: '0' sysctl_file: /etc/sysctl.conf @@ -85893,6 +97807,10 @@ fi - reboot_required - sysctl_kernel_core_uses_pid + + + + @@ -85906,8 +97824,6 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.dmesg_restrict = 1 3.1.5 - CCI-001082 - CCI-001090 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -85918,12 +97834,13 @@ To make sure that the setting is persistent, add the following line to a file in SI-11(a) SI-11(b) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000138-GPOS-00069 - SRG-APP-000243-CTR-000600 + SRG-OS-000132-GPOS-00067 + SRG-OS-000138-GPOS-00069 + SRG-APP-000243-CTR-000600 R9 - OL09-00-002406 - SV-271745r1091947_rule + 1546 + OL09-00-002406 + SV-271745r1117266_rule Unprivileged access to the kernel syslog can expose sensitive kernel address information. @@ -85958,7 +97875,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.dmesg_restrict # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.dmesg_restrict="1" fi @@ -86006,16 +97923,12 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Restrict Access to Kernel Message Buffer - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.dmesg_restrict.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002406 @@ -86029,13 +97942,60 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict -- name: Comment out any occurrences of kernel.dmesg_restrict from config files - replace: - path: '{{ item.path }}' +- name: Restrict Access to Kernel Message Buffer - Find all files that contain kernel.dmesg_restrict + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.dmesg_restrict\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: Restrict Access to Kernel Message Buffer - Find all files that set kernel.dmesg_restrict + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.dmesg_restrict\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: Restrict Access to Kernel Message Buffer - Comment out any occurrences of + kernel.dmesg_restrict from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.dmesg_restrict replace: '#kernel.dmesg_restrict' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002406 - NIST-800-171-3.1.5 @@ -86048,8 +98008,9 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict -- name: Ensure sysctl kernel.dmesg_restrict is set to 1 - sysctl: +- name: Restrict Access to Kernel Message Buffer - Ensure sysctl kernel.dmesg_restrict + is set to 1 + ansible.posix.sysctl: name: kernel.dmesg_restrict value: '1' sysctl_file: /etc/sysctl.conf @@ -86068,6 +98029,10 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict + + + + @@ -86080,14 +98045,13 @@ fi To set the runtime status of the kernel.kexec_load_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.kexec_load_disabled=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kexec_load_disabled = 1 - CCI-003992 - CCI-000366 CM-6 FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000366-GPOS-00153 - OL09-00-002428 - SV-271766r1092010_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000366-GPOS-00153 + 1409 + OL09-00-002428 + SV-271766r1092010_rule Disabling kexec_load allows greater control of the kernel memory. It makes it impossible to load another kernel image after it has been disabled. @@ -86123,7 +98087,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.kexec_load_disabled # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.kexec_load_disabled="1" fi @@ -86169,16 +98133,12 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Image Loading - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.kexec_load_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002428 @@ -86190,13 +98150,56 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled -- name: Comment out any occurrences of kernel.kexec_load_disabled from config files - replace: - path: '{{ item.path }}' +- name: Disable Kernel Image Loading - Find all files that contain kernel.kexec_load_disabled + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kexec_load_disabled\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: Disable Kernel Image Loading - Find all files that set kernel.kexec_load_disabled + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kexec_load_disabled\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: Disable Kernel Image Loading - Comment out any occurrences of kernel.kexec_load_disabled + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.kexec_load_disabled replace: '#kernel.kexec_load_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002428 - NIST-800-53-CM-6 @@ -86207,8 +98210,9 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled -- name: Ensure sysctl kernel.kexec_load_disabled is set to 1 - sysctl: +- name: Disable Kernel Image Loading - Ensure sysctl kernel.kexec_load_disabled is + set to 1 + ansible.posix.sysctl: name: kernel.kexec_load_disabled value: '1' sysctl_file: /etc/sysctl.conf @@ -86225,6 +98229,10 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled + + + + @@ -86245,6 +98253,10 @@ that once this option has been set, it cannot be reverted without doing a system reboot. Make sure that all needed kernel modules are loaded before setting this option. + + + + @@ -86294,7 +98306,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.panic_on_oops # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.panic_on_oops="1" fi @@ -86338,16 +98350,12 @@ fi - reboot_required - sysctl_kernel_panic_on_oops -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Kernel panic on oops - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.panic_on_oops.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86357,13 +98365,52 @@ fi - reboot_required - sysctl_kernel_panic_on_oops -- name: Comment out any occurrences of kernel.panic_on_oops from config files - replace: - path: '{{ item.path }}' +- name: Kernel panic on oops - Find all files that contain kernel.panic_on_oops + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.panic_on_oops\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: Kernel panic on oops - Find all files that set kernel.panic_on_oops to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.panic_on_oops\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: Kernel panic on oops - Comment out any occurrences of kernel.panic_on_oops + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.panic_on_oops replace: '#kernel.panic_on_oops' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86372,8 +98419,8 @@ fi - reboot_required - sysctl_kernel_panic_on_oops -- name: Ensure sysctl kernel.panic_on_oops is set to 1 - sysctl: +- name: Kernel panic on oops - Ensure sysctl kernel.panic_on_oops is set to 1 + ansible.posix.sysctl: name: kernel.panic_on_oops value: '1' sysctl_file: /etc/sysctl.conf @@ -86388,6 +98435,10 @@ fi - reboot_required - sysctl_kernel_panic_on_oops + + + + @@ -86401,7 +98452,7 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_cpu_time_max_percent = 1 R9 - The kernel.perf_cpu_time_max_percent configures a treshold of + The kernel.perf_cpu_time_max_percent configures a threshold of maximum percentile of CPU that can be used by Perf system. Restricting usage of Perf system decreases risk of potential availability problems. @@ -86436,7 +98487,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.perf_cpu_time_max_percent # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.perf_cpu_time_max_percent="1" fi @@ -86480,16 +98531,12 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Limit CPU consumption of the Perf system - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_cpu_time_max_percent.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86499,14 +98546,52 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent -- name: Comment out any occurrences of kernel.perf_cpu_time_max_percent from config - files - replace: - path: '{{ item.path }}' +- name: Limit CPU consumption of the Perf system - Find all files that contain kernel.perf_cpu_time_max_percent + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_cpu_time_max_percent\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: Limit CPU consumption of the Perf system - Find all files that set kernel.perf_cpu_time_max_percent + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_cpu_time_max_percent\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: Limit CPU consumption of the Perf system - Comment out any occurrences of + kernel.perf_cpu_time_max_percent from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.perf_cpu_time_max_percent replace: '#kernel.perf_cpu_time_max_percent' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86515,8 +98600,9 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent -- name: Ensure sysctl kernel.perf_cpu_time_max_percent is set to 1 - sysctl: +- name: Limit CPU consumption of the Perf system - Ensure sysctl kernel.perf_cpu_time_max_percent + is set to 1 + ansible.posix.sysctl: name: kernel.perf_cpu_time_max_percent value: '1' sysctl_file: /etc/sysctl.conf @@ -86531,6 +98617,10 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent + + + + @@ -86580,7 +98670,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.perf_event_max_sample_rate # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.perf_event_max_sample_rate="1" fi @@ -86624,16 +98714,12 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Limit sampling frequency of the Perf system - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_event_max_sample_rate.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86643,14 +98729,53 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate -- name: Comment out any occurrences of kernel.perf_event_max_sample_rate from config - files - replace: - path: '{{ item.path }}' +- name: Limit sampling frequency of the Perf system - Find all files that contain + kernel.perf_event_max_sample_rate + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_max_sample_rate\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: Limit sampling frequency of the Perf system - Find all files that set kernel.perf_event_max_sample_rate + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_max_sample_rate\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: Limit sampling frequency of the Perf system - Comment out any occurrences + of kernel.perf_event_max_sample_rate from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.perf_event_max_sample_rate replace: '#kernel.perf_event_max_sample_rate' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86659,8 +98784,9 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate -- name: Ensure sysctl kernel.perf_event_max_sample_rate is set to 1 - sysctl: +- name: Limit sampling frequency of the Perf system - Ensure sysctl kernel.perf_event_max_sample_rate + is set to 1 + ansible.posix.sysctl: name: kernel.perf_event_max_sample_rate value: '1' sysctl_file: /etc/sysctl.conf @@ -86675,6 +98801,10 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate + + + + @@ -86687,16 +98817,14 @@ fi To set the runtime status of the kernel.perf_event_paranoid kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_event_paranoid=2 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_event_paranoid = 2 - CCI-001082 - CCI-001090 AC-6 FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000138-GPOS-00069 - SRG-APP-000243-CTR-000600 + SRG-OS-000132-GPOS-00067 + SRG-OS-000138-GPOS-00069 + SRG-APP-000243-CTR-000600 R9 - OL09-00-002407 - SV-271746r1091950_rule + OL09-00-002407 + SV-271746r1117266_rule Kernel profiling can reveal sensitive information about kernel behaviour. # Remediation is applicable only in certain platforms @@ -86730,7 +98858,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.perf_event_paranoid # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.perf_event_paranoid="2" fi @@ -86776,16 +98904,12 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disallow kernel profiling by unprivileged users - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_event_paranoid.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002407 @@ -86797,13 +98921,57 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid -- name: Comment out any occurrences of kernel.perf_event_paranoid from config files - replace: - path: '{{ item.path }}' +- name: Disallow kernel profiling by unprivileged users - Find all files that contain + kernel.perf_event_paranoid + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_paranoid\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: Disallow kernel profiling by unprivileged users - Find all files that set + kernel.perf_event_paranoid to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_paranoid\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: Disallow kernel profiling by unprivileged users - Comment out any occurrences + of kernel.perf_event_paranoid from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.perf_event_paranoid replace: '#kernel.perf_event_paranoid' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002407 - NIST-800-53-AC-6 @@ -86814,8 +98982,9 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid -- name: Ensure sysctl kernel.perf_event_paranoid is set to 2 - sysctl: +- name: Disallow kernel profiling by unprivileged users - Ensure sysctl kernel.perf_event_paranoid + is set to 2 + ansible.posix.sysctl: name: kernel.perf_event_paranoid value: '2' sysctl_file: /etc/sysctl.conf @@ -86832,6 +99001,10 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid + + + + @@ -86881,7 +99054,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.pid_max # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.pid_max="65536" fi @@ -86925,16 +99098,12 @@ fi - reboot_required - sysctl_kernel_pid_max -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Configure maximum number of process identifiers - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.pid_max.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86944,13 +99113,53 @@ fi - reboot_required - sysctl_kernel_pid_max -- name: Comment out any occurrences of kernel.pid_max from config files - replace: - path: '{{ item.path }}' +- name: Configure maximum number of process identifiers - Find all files that contain + kernel.pid_max + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.pid_max\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: Configure maximum number of process identifiers - Find all files that set + kernel.pid_max to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.pid_max\s*=\s*65536$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: Configure maximum number of process identifiers - Comment out any occurrences + of kernel.pid_max from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.pid_max replace: '#kernel.pid_max' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86959,8 +99168,9 @@ fi - reboot_required - sysctl_kernel_pid_max -- name: Ensure sysctl kernel.pid_max is set to 65536 - sysctl: +- name: Configure maximum number of process identifiers - Ensure sysctl kernel.pid_max + is set to 65536 + ansible.posix.sysctl: name: kernel.pid_max value: '65536' sysctl_file: /etc/sysctl.conf @@ -86975,6 +99185,10 @@ fi - reboot_required - sysctl_kernel_pid_max + + + + @@ -87024,7 +99238,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.sysrq # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.sysrq="0" fi @@ -87068,16 +99282,12 @@ fi - reboot_required - sysctl_kernel_sysrq -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disallow magic SysRq key - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.sysrq.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -87087,13 +99297,52 @@ fi - reboot_required - sysctl_kernel_sysrq -- name: Comment out any occurrences of kernel.sysrq from config files - replace: - path: '{{ item.path }}' +- name: Disallow magic SysRq key - Find all files that contain kernel.sysrq + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.sysrq\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: Disallow magic SysRq key - Find all files that set kernel.sysrq to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.sysrq\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: Disallow magic SysRq key - Comment out any occurrences of kernel.sysrq from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.sysrq replace: '#kernel.sysrq' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -87102,8 +99351,8 @@ fi - reboot_required - sysctl_kernel_sysrq -- name: Ensure sysctl kernel.sysrq is set to 0 - sysctl: +- name: Disallow magic SysRq key - Ensure sysctl kernel.sysrq is set to 0 + ansible.posix.sysctl: name: kernel.sysrq value: '0' sysctl_file: /etc/sysctl.conf @@ -87118,6 +99367,10 @@ fi - reboot_required - sysctl_kernel_sysrq + + + + @@ -87130,15 +99383,14 @@ fi To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.unprivileged_bpf_disabled=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.unprivileged_bpf_disabled = 1 - CCI-000366 - CCI-001082 AC-6 SC-7(10) - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 R9 - OL09-00-002409 - SV-271748r1091956_rule + 1409 + OL09-00-002409 + SV-271748r1117266_rule Loading and accessing the packet filters programs and maps using the bpf() syscall has the potential of revealing sensitive information about the kernel state. @@ -87173,7 +99425,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.unprivileged_bpf_disabled # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.unprivileged_bpf_disabled="1" fi @@ -87220,16 +99472,13 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.unprivileged_bpf_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002409 @@ -87242,14 +99491,59 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled -- name: Comment out any occurrences of kernel.unprivileged_bpf_disabled from config - files - replace: - path: '{{ item.path }}' +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that contain kernel.unprivileged_bpf_disabled + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that set kernel.unprivileged_bpf_disabled to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Comment + out any occurrences of kernel.unprivileged_bpf_disabled from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.unprivileged_bpf_disabled replace: '#kernel.unprivileged_bpf_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002409 - NIST-800-53-AC-6 @@ -87261,8 +99555,9 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled -- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set to 1 - sysctl: +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Ensure + sysctl kernel.unprivileged_bpf_disabled is set to 1 + ansible.posix.sysctl: name: kernel.unprivileged_bpf_disabled value: '1' sysctl_file: /etc/sysctl.conf @@ -87280,6 +99575,10 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled + + + + @@ -87317,12 +99616,11 @@ To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.unprivileged_bpf_disabled = 2 - CCI-000366 AC-6 SC-7(10) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 Loading and accessing the packet filters programs and maps using the bpf() syscall has the potential of revealing sensitive information about the kernel state. @@ -87359,7 +99657,7 @@ sysctl_kernel_unprivileged_bpf_disabled_value=' tags: - always -- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set - sysctl: +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that contain kernel.unprivileged_bpf_disabled + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that set kernel.unprivileged_bpf_disabled to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*{{ sysctl_kernel_unprivileged_bpf_disabled_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Comment + out any occurrences of kernel.unprivileged_bpf_disabled from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*kernel.unprivileged_bpf_disabled + replace: '#kernel.unprivileged_bpf_disabled' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Ensure + sysctl kernel.unprivileged_bpf_disabled is set + ansible.posix.sysctl: name: kernel.unprivileged_bpf_disabled value: '{{ sysctl_kernel_unprivileged_bpf_disabled_value }}' sysctl_file: /etc/sysctl.conf @@ -87467,6 +99807,10 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled_accept_default + + + + @@ -87479,15 +99823,14 @@ fi To set the runtime status of the kernel.yama.ptrace_scope kernel parameter, run the following command: $ sudo sysctl -w kernel.yama.ptrace_scope=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.yama.ptrace_scope = 1 - CCI-000366 - CCI-001082 SC-7(10) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 R11 - OL09-00-002410 - SV-271749r1091959_rule + 1409 + OL09-00-002410 + SV-271749r1117266_rule Unrestricted usage of ptrace allows compromised binaries to run ptrace on another processes of the user. Like this, the attacker can steal sensitive information from the target processes (e.g. SSH sessions, web browser, ...) @@ -87525,7 +99868,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.yama.ptrace_scope # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.yama.ptrace_scope="1" fi @@ -87571,16 +99914,12 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Restrict usage of ptrace to descendant processes - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.yama.ptrace_scope.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002410 @@ -87592,13 +99931,57 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope -- name: Comment out any occurrences of kernel.yama.ptrace_scope from config files - replace: - path: '{{ item.path }}' +- name: Restrict usage of ptrace to descendant processes - Find all files that contain + kernel.yama.ptrace_scope + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.yama.ptrace_scope\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: Restrict usage of ptrace to descendant processes - Find all files that set + kernel.yama.ptrace_scope to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.yama.ptrace_scope\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: Restrict usage of ptrace to descendant processes - Comment out any occurrences + of kernel.yama.ptrace_scope from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.yama.ptrace_scope replace: '#kernel.yama.ptrace_scope' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002410 - NIST-800-53-SC-7(10) @@ -87609,8 +99992,9 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope -- name: Ensure sysctl kernel.yama.ptrace_scope is set to 1 - sysctl: +- name: Restrict usage of ptrace to descendant processes - Ensure sysctl kernel.yama.ptrace_scope + is set to 1 + ansible.posix.sysctl: name: kernel.yama.ptrace_scope value: '1' sysctl_file: /etc/sysctl.conf @@ -87627,6 +100011,10 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope + + + + @@ -87639,13 +100027,13 @@ fi To set the runtime status of the net.core.bpf_jit_harden kernel parameter, run the following command: $ sudo sysctl -w net.core.bpf_jit_harden=2 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.core.bpf_jit_harden = 2 - CCI-000366 CM-6 SC-7(10) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 - OL09-00-002430 - SV-271768r1092016_rule + 1409 + OL09-00-002430 + SV-271768r1092016_rule When hardened, the extended Berkeley Packet Filter just-in-time compiler will randomize any kernel addresses in the BPF programs and maps, and will not expose the JIT addresses in /proc/kallsyms. @@ -87681,7 +100069,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.core.bpf_jit_harden # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.core.bpf_jit_harden="2" fi @@ -87728,16 +100116,13 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Harden the operation of the BPF just-in-time compiler - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.core.bpf_jit_harden.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002430 @@ -87750,13 +100135,59 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden -- name: Comment out any occurrences of net.core.bpf_jit_harden from config files - replace: - path: '{{ item.path }}' +- name: Harden the operation of the BPF just-in-time compiler - Find all files that + contain net.core.bpf_jit_harden + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.core.bpf_jit_harden\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: Harden the operation of the BPF just-in-time compiler - Find all files that + set net.core.bpf_jit_harden to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.core.bpf_jit_harden\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: Harden the operation of the BPF just-in-time compiler - Comment out any occurrences + of net.core.bpf_jit_harden from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.core.bpf_jit_harden replace: '#net.core.bpf_jit_harden' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002430 - NIST-800-53-CM-6 @@ -87768,8 +100199,9 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden -- name: Ensure sysctl net.core.bpf_jit_harden is set to 2 - sysctl: +- name: Harden the operation of the BPF just-in-time compiler - Ensure sysctl net.core.bpf_jit_harden + is set to 2 + ansible.posix.sysctl: name: net.core.bpf_jit_harden value: '2' sysctl_file: /etc/sysctl.conf @@ -87787,6 +100219,10 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden + + + + @@ -87805,16 +100241,17 @@ add the following line to a file in the directory /etc/sysctl.duser.max_user_namespaces = 0 When containers are deployed on the machine, the value should be set to large non-zero value. - This configuration baseline was created to deploy the base operating system for general purpose -workloads. When the operating system is configured for certain purposes, such as to host Linux Containers, -it is expected that user.max_user_namespaces will be enabled. - CCI-000366 + Remediation of this rule might impair or prevent functionality of certain applications. +This stands especially for general container usage and for certain desktop applications. +There is an alternative rule which performs the same check but it intentionally lacks the remediation part. +If needed, you can use the rule sysctl_user_max_user_namespaces_no_remediation. +In that case, ensure that such use case is properly documented. SC-39 CM-6(a) FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-002370 - SV-271727r1091893_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002370 + SV-271727r1091893_rule It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or system objectives. These unnecessary capabilities or services are often overlooked and therefore may remain unsecured. They increase the risk to the platform by providing additional attack vectors. @@ -87852,7 +100289,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for user.max_user_namespaces # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w user.max_user_namespaces="0" fi @@ -87899,16 +100336,12 @@ fi - reboot_required - sysctl_user_max_user_namespaces -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable the use of user namespaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*user.max_user_namespaces.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002370 @@ -87921,13 +100354,58 @@ fi - reboot_required - sysctl_user_max_user_namespaces -- name: Comment out any occurrences of user.max_user_namespaces from config files - replace: - path: '{{ item.path }}' +- name: Disable the use of user namespaces - Find all files that contain user.max_user_namespaces + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*user.max_user_namespaces\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: Disable the use of user namespaces - Find all files that set user.max_user_namespaces + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*user.max_user_namespaces\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: Disable the use of user namespaces - Comment out any occurrences of user.max_user_namespaces + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*user.max_user_namespaces replace: '#user.max_user_namespaces' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002370 - NIST-800-53-CM-6(a) @@ -87939,8 +100417,9 @@ fi - reboot_required - sysctl_user_max_user_namespaces -- name: Ensure sysctl user.max_user_namespaces is set to 0 - sysctl: +- name: Disable the use of user namespaces - Ensure sysctl user.max_user_namespaces + is set to 0 + ansible.posix.sysctl: name: user.max_user_namespaces value: '0' sysctl_file: /etc/sysctl.conf @@ -87958,6 +100437,10 @@ fi - reboot_required - sysctl_user_max_user_namespaces + + + + @@ -88007,7 +100490,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for vm.mmap_min_addr # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w vm.mmap_min_addr="65536" fi @@ -88051,16 +100534,13 @@ fi - reboot_required - sysctl_vm_mmap_min_addr -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Prevent applications from mapping low portion of virtual memory - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*vm.mmap_min_addr.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -88070,13 +100550,53 @@ fi - reboot_required - sysctl_vm_mmap_min_addr -- name: Comment out any occurrences of vm.mmap_min_addr from config files - replace: - path: '{{ item.path }}' +- name: Prevent applications from mapping low portion of virtual memory - Find all + files that contain vm.mmap_min_addr + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*vm.mmap_min_addr\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: Prevent applications from mapping low portion of virtual memory - Find all + files that set vm.mmap_min_addr to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*vm.mmap_min_addr\s*=\s*65536$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: Prevent applications from mapping low portion of virtual memory - Comment + out any occurrences of vm.mmap_min_addr from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*vm.mmap_min_addr replace: '#vm.mmap_min_addr' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -88085,8 +100605,9 @@ fi - reboot_required - sysctl_vm_mmap_min_addr -- name: Ensure sysctl vm.mmap_min_addr is set to 65536 - sysctl: +- name: Prevent applications from mapping low portion of virtual memory - Ensure sysctl + vm.mmap_min_addr is set to 65536 + ansible.posix.sysctl: name: vm.mmap_min_addr value: '65536' sysctl_file: /etc/sysctl.conf @@ -88101,6 +100622,10 @@ fi - reboot_required - sysctl_vm_mmap_min_addr + + + + @@ -88130,17 +100655,17 @@ The core dumps of setuid programs are further protected. The sysctl variable fs.suid_dumpable controls whether the kernel allows core dumps from these programs at all. The default value of 0 is recommended. + Disable acquiring, saving, and processing core dumps The systemd-coredump.socket unit is a socket activation of the systemd-coredump@.service which processes core dumps. By masking the unit, core dump processing is disabled. - CCI-000366 SC-7(10) FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-002384 - SV-271732r1091908_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002384 + SV-271732r1091908_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems. @@ -88181,6 +100706,7 @@ fi cmd: systemctl -q list-unit-files --type socket register: result_systemd_unit_files changed_when: false + check_mode: false when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002384 @@ -88212,6 +100738,10 @@ fi - no_reboot_needed - service_systemd-coredump_disabled + + + + @@ -88222,22 +100752,21 @@ fi Disable core dump backtraces The ProcessSizeMax option in [Coredump] section -of /etc/systemd/coredump.conf -specifies the maximum size in bytes of a core which will be processed. -Core dumps exceeding this size may be stored, but the backtrace will not -be generated. - If the /etc/systemd/coredump.conf file +of /etc/systemd/coredump.conf or in a drop-in file under +/etc/systemd/coredump.conf.d/ specifies the maximum size in bytes +of a core which will be processed. Core dumps exceeding this size may be +stored, but the backtrace will not be generated. + If the /etc/systemd/coredump.conf file or a drop-in file under /etc/systemd/coredump.conf.d/ does not already contain the [Coredump] section, the value will not be configured correctly. - CCI-000366 CM-6 Req-3.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002381 - SV-271729r1091899_rule + OL09-00-002381 + SV-271729r1091899_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to @@ -88245,26 +100774,29 @@ debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced -debuging. Permitting temporary enablement of core dumps during such situations +debugging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy. # Remediation is applicable only in certain platforms -if rpm --quiet -q systemd; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q systemd; }; then found=false # set value in all files if they contain section or key -for f in $(echo -n "/etc/systemd/coredump.conf"); do +for f in $(echo -n "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf"); do if [ ! -e "$f" ]; then continue fi # find key in section and change value if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*ProcessSizeMax" "$f"; then + if ! grep -qPz "ProcessSizeMax=0" "$f"; then sed -i "s/ProcessSizeMax[^(\n)]*/ProcessSizeMax=0/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then @@ -88277,7 +100809,7 @@ done # if section not in any file, append section with key = value to FIRST file in files parameter if ! $found ; then - file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ') + file=$(echo "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf" | cut -f1 -d ' ') mkdir -p "$(dirname "$file")" echo -e "[Coredump]\nProcessSizeMax=0" >> "$file" @@ -88305,15 +100837,99 @@ fi - no_reboot_needed - restrict_strategy -- name: Set 'ProcessSizeMax' to '0' in the [Coredump] section of '/etc/systemd/coredump.conf' - ini_file: - path: /etc/systemd/coredump.conf +- name: Disable core dump backtraces - Search for a section in files + ansible.builtin.find: + paths: '{{item.path}}' + patterns: '{{item.pattern}}' + contains: ^\s*\[Coredump\] + read_whole_file: true + use_regex: true + register: systemd_dropin_files_with_section + loop: + - path: '{{ ''/etc/systemd/coredump.conf'' | dirname }}' + pattern: '{{ ''/etc/systemd/coredump.conf'' | basename | regex_escape }}' + - path: /etc/systemd/coredump.conf.d + pattern: .*\.conf + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dump backtraces - Count number of files which contain the correct + section + ansible.builtin.set_fact: + count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results + | map(attribute=''matched'') | list | map(''int'') | sum}}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dump backtraces - Add missing configuration to correct section + community.general.ini_file: + path: '{{item}}' section: Coredump option: ProcessSizeMax value: '0' + state: present + no_extra_spaces: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int > 0 + loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[]) + | map(attribute=''path'') | list }}' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dump backtraces - Add configuration to new remediation file + community.general.ini_file: + path: /etc/systemd/coredump.conf.d/complianceascode_hardening.conf + section: Coredump + option: ProcessSizeMax + value: '0' + state: present + no_extra_spaces: true create: true - mode: 420 - when: '"systemd" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int == 0 tags: - DISA-STIG-OL09-00-002381 - NIST-800-53-CM-6 @@ -88337,45 +100953,49 @@ fi Disable storing core dump - The Storage option in [Coredump] sectionof /etc/systemd/coredump.conf + The Storage option in [Coredump] section +of /etc/systemd/coredump.conf or a drop-in file in +/etc/systemd/coredump.conf.d/*.conf can be set to none to disable storing core dumps permanently. - If the /etc/systemd/coredump.conf file + If the /etc/systemd/coredump.conf file or a drop-in file under /etc/systemd/coredump.conf.d/ does not already contain the [Coredump] section, the value will not be configured correctly. - CCI-000366 CM-6 Req-3.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002382 - SV-271730r1091902_rule + OL09-00-002382 + SV-271730r1091902_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced -debuging. Permitting temporary enablement of core dumps during such situations +debugging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy. # Remediation is applicable only in certain platforms -if rpm --quiet -q systemd; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q systemd; }; then found=false # set value in all files if they contain section or key -for f in $(echo -n "/etc/systemd/coredump.conf"); do +for f in $(echo -n "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf"); do if [ ! -e "$f" ]; then continue fi # find key in section and change value if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*Storage" "$f"; then + if ! grep -qPz "Storage=none" "$f"; then sed -i "s/Storage[^(\n)]*/Storage=none/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then @@ -88388,7 +101008,7 @@ done # if section not in any file, append section with key = value to FIRST file in files parameter if ! $found ; then - file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ') + file=$(echo "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf" | cut -f1 -d ' ') mkdir -p "$(dirname "$file")" echo -e "[Coredump]\nStorage=none" >> "$file" @@ -88416,15 +101036,99 @@ fi - no_reboot_needed - restrict_strategy -- name: Set 'Storage' to 'none' in the [Coredump] section of '/etc/systemd/coredump.conf' - ini_file: - path: /etc/systemd/coredump.conf +- name: Disable storing core dump - Search for a section in files + ansible.builtin.find: + paths: '{{item.path}}' + patterns: '{{item.pattern}}' + contains: ^\s*\[Coredump\] + read_whole_file: true + use_regex: true + register: systemd_dropin_files_with_section + loop: + - path: '{{ ''/etc/systemd/coredump.conf'' | dirname }}' + pattern: '{{ ''/etc/systemd/coredump.conf'' | basename | regex_escape }}' + - path: /etc/systemd/coredump.conf.d + pattern: .*\.conf + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable storing core dump - Count number of files which contain the correct + section + ansible.builtin.set_fact: + count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results + | map(attribute=''matched'') | list | map(''int'') | sum}}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable storing core dump - Add missing configuration to correct section + community.general.ini_file: + path: '{{item}}' section: Coredump option: Storage value: none + state: present + no_extra_spaces: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int > 0 + loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[]) + | map(attribute=''path'') | list }}' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable storing core dump - Add configuration to new remediation file + community.general.ini_file: + path: /etc/systemd/coredump.conf.d/complianceascode_hardening.conf + section: Coredump + option: Storage + value: none + state: present + no_extra_spaces: true create: true - mode: 420 - when: '"systemd" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int == 0 tags: - DISA-STIG-OL09-00-002382 - NIST-800-53-CM-6 @@ -88466,7 +101170,6 @@ fi DSS01.03 DSS03.05 DSS05.07 - CCI-000366 SR 6.2 SR 7.1 SR 7.2 @@ -88476,29 +101179,40 @@ fi SC-7(10) DE.CM-1 PR.DS-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002383 - SV-271731r1091905_rule + OL09-00-002383 + SV-271731r1091905_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then SECURITY_LIMITS_FILE="/etc/security/limits.conf" +DROPIN_DIR="/etc/security/limits.d" +DROPIN_FILE="$DROPIN_DIR/10-ssg-hardening.conf" +REGEX_CORRECT_VALUE="^\s*\*\s+hard\s+core\s+0\s*$" -if grep -qE '^\s*\*\s+hard\s+core' $SECURITY_LIMITS_FILE; then - sed -ri 's/(hard\s+core\s+)[[:digit:]]+/\1 0/' $SECURITY_LIMITS_FILE -else - echo "* hard core 0" >> $SECURITY_LIMITS_FILE +# Remove bad configuration in drop-ins +if [ -d "$DROPIN_DIR" ]; then + for override in "$DROPIN_DIR"/*.conf; do + if [ -f "$override" ] && ! grep -qE "$REGEX_CORRECT_VALUE" "$override"; then + sed -ir -E '/^[[:space:]]*\*[[:space:]]+hard[[:space:]]+core[[:space:]]+/ s/^/#/' "$override" + fi + done fi -if ls /etc/security/limits.d/*.conf > /dev/null; then - sed -ri '/^\s*\*\s+hard\s+core/d' /etc/security/limits.d/*.conf +if [ -d "$DROPIN_DIR" ] && grep -qEr "$REGEX_CORRECT_VALUE" "$DROPIN_DIR"; then + exit 0 +elif [ ! -d "$DROPIN_DIR" ] && grep -qE "$REGEX_CORRECT_VALUE" "$SECURITY_LIMITS_FILE"; then + exit 0 +else + mkdir -p "$DROPIN_DIR" + echo "* hard core 0" >> $DROPIN_FILE fi else @@ -88522,13 +101236,204 @@ fi - no_reboot_needed - restrict_strategy -- name: Disable core dumps with limits - lineinfile: - dest: /etc/security/limits.conf - regexp: ^[^#].*core - line: '* hard core 0' - create: true - when: '"pam" in ansible_facts.packages' +- name: Disable Core Dumps for All Users - Set dirs, files and regex variables + ansible.builtin.set_fact: + limits_dropin_dir: /etc/security/limits.d + limits_dropin_file: /etc/security/limits.d/10-ssg-hardening.conf + limits_main_file: /etc/security/limits.conf + limits_correct_regex: ^\s*\*\s+hard\s+core\s+0\s*$ + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Find valid drop-ins for core limit + ansible.builtin.find: + paths: '{{ limits_dropin_dir }}' + patterns: '*.conf' + contains: '{{ limits_correct_regex }}' + file_type: file + register: valid_dropins + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Find all drop-ins with any core limit + ansible.builtin.find: + paths: '{{ limits_dropin_dir }}' + patterns: '*.conf' + contains: ^\s*\*\s+hard\s+core\s+ + file_type: file + register: all_dropins + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Get invalid drop-ins + ansible.builtin.set_fact: + invalid_dropins: '{{ all_dropins.files | rejectattr(''path'', ''in'', valid_dropins.files + | map(attribute=''path'') | list) | map(attribute=''path'') | list }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Comment invalid * hard core lines in drop-ins + ansible.builtin.replace: + path: '{{ item }}' + regexp: (^\s*\*\s+hard\s+core\s+.*$) + replace: '#\1' + loop: '{{ invalid_dropins }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - invalid_dropins | length > 0 + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Check if main limits.conf contains correct + core limit + ansible.builtin.find: + paths: /etc/security + patterns: limits.conf + contains: '{{ limits_correct_regex }}' + file_type: file + register: main_valid + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not (valid_dropins.matched | default(0) > 0) + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Set fact if configuration is valid + ansible.builtin.set_fact: + core_limit_valid: '{{ (valid_dropins.matched | default(0)) > 0 or (main_valid.matched + | default(0)) > 0 }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Ensure drop-in directory exists + ansible.builtin.file: + path: '{{ limits_dropin_dir }}' + state: directory + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not core_limit_valid + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Deploy 10-ssg-hardening.conf drop-in with + correct core limit + ansible.builtin.copy: + dest: '{{ limits_dropin_file }}' + content: | + * hard core 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not core_limit_valid tags: - DISA-STIG-OL09-00-002383 - NIST-800-53-CM-6 @@ -88606,7 +101511,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.suid_dumpable # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.suid_dumpable="0" fi @@ -88655,16 +101560,12 @@ fi - reboot_required - sysctl_fs_suid_dumpable -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Core Dumps for SUID programs - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.suid_dumpable.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-SI-11(a) @@ -88679,13 +101580,62 @@ fi - reboot_required - sysctl_fs_suid_dumpable -- name: Comment out any occurrences of fs.suid_dumpable from config files - replace: - path: '{{ item.path }}' +- name: Disable Core Dumps for SUID programs - Find all files that contain fs.suid_dumpable + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.suid_dumpable\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: Disable Core Dumps for SUID programs - Find all files that set fs.suid_dumpable + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.suid_dumpable\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: Disable Core Dumps for SUID programs - Comment out any occurrences of fs.suid_dumpable + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.suid_dumpable replace: '#fs.suid_dumpable' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-53-SI-11(a) - NIST-800-53-SI-11(b) @@ -88699,8 +101649,9 @@ fi - reboot_required - sysctl_fs_suid_dumpable -- name: Ensure sysctl fs.suid_dumpable is set to 0 - sysctl: +- name: Disable Core Dumps for SUID programs - Ensure sysctl fs.suid_dumpable is set + to 0 + ansible.posix.sysctl: name: fs.suid_dumpable value: '0' sysctl_file: /etc/sysctl.conf @@ -88720,6 +101671,10 @@ fi - reboot_required - sysctl_fs_suid_dumpable + + + + @@ -88757,7 +101712,6 @@ ExecShield or is disabled in /etc/default/grub.APO13.01 DSS05.02 3.1.7 - CCI-002824 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -88781,9 +101735,10 @@ ExecShield or is disabled in /etc/default/grub.SC-39 CM-6(a) PR.PT-4 - SRG-OS-000433-GPOS-00192 - OL09-00-002422 - SV-271760r1091992_rule + SRG-OS-000433-GPOS-00192 + 1409 + OL09-00-002422 + SV-271760r1091992_rule ExecShield uses the segmentation feature on all x86 systems to prevent execution in memory higher than a certain address. It writes an address as a limit in the code segment descriptor, to control where code can be @@ -88791,9 +101746,9 @@ executed, on a per-process basis. When the kernel places a process's memory regions such as the stack and heap higher than this address, the hardware prevents execution in that address range. This is enabled by default on the latest Red Hat and Fedora systems if supported by the hardware. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( rpm --quiet -q kernel || rpm --quiet -q kernel-uek && ( grep -sqE "^.*\.x86_64$" /proc/sys/kernel/osrelease || grep -sqE "^x86_64$" /proc/sys/kernel/arch; ) ); then grubby --update-kernel=ALL --remove-args=noexec @@ -88816,9 +101771,51 @@ fi - restrict_strategy - sysctl_kernel_exec_shield +- name: Check if noexec argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub + when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + and ansible_architecture == "x86_64" ) + tags: + - DISA-STIG-OL09-00-002422 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - sysctl_kernel_exec_shield + +- name: Check if noexec argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + and ansible_architecture == "x86_64" ) + tags: + - DISA-STIG-OL09-00-002422 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - sysctl_kernel_exec_shield + - name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="noexec" - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="noexec" + when: + - ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + and ansible_architecture == "x86_64" ) + - (grubby_info.stdout is search('noexec')) or ((etc_default_grub['content'] | b64decode) + is search('noexec')) tags: - DISA-STIG-OL09-00-002422 - NIST-800-171-3.1.7 @@ -88845,43 +101842,41 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kptr_restrict = - CCI-000366 - CCI-002824 - CCI-001082 - CIP-002-5 R1.1 - CIP-002-5 R1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 4.1 - CIP-004-6 4.2 - CIP-004-6 R2.2.3 - CIP-004-6 R2.2.4 - CIP-004-6 R2.3 - CIP-004-6 R4 - CIP-005-6 R1 - CIP-005-6 R1.1 - CIP-005-6 R1.2 - CIP-007-3 R3 - CIP-007-3 R3.1 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R8.4 - CIP-009-6 R.1.1 - CIP-009-6 R4 + CIP-002-5 R1.1 + CIP-002-5 R1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 4.1 + CIP-004-6 4.2 + CIP-004-6 R2.2.3 + CIP-004-6 R2.2.4 + CIP-004-6 R2.3 + CIP-004-6 R4 + CIP-005-6 R1 + CIP-005-6 R1.1 + CIP-005-6 R1.2 + CIP-007-3 R3 + CIP-007-3 R3.1 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R8.4 + CIP-009-6 R.1.1 + CIP-009-6 R4 SC-30 SC-30(2) SC-30(5) CM-6(a) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000433-GPOS-00192 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000433-GPOS-00192 + SRG-OS-000480-GPOS-00227 R9 - OL09-00-002408 - SV-271747r1091953_rule + 1409 + OL09-00-002408 + SV-271747r1117266_rule Exposing kernel pointers (through procfs or seq_printf()) exposes kernel writeable structures which may contain functions pointers. If a write vulnerability occurs in the kernel, allowing write access to any of this structure, the kernel can @@ -88921,7 +101916,7 @@ sysctl_kernel_kptr_restrict_value=' tags: - always -- name: Ensure sysctl kernel.kptr_restrict is set - sysctl: +- name: Restrict Exposed Kernel Pointer Addresses Access - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Find all files that contain + kernel.kptr_restrict + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kptr_restrict\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Find all files that set + kernel.kptr_restrict to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kptr_restrict\s*=\s*{{ sysctl_kernel_kptr_restrict_value }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Comment out any occurrences + of kernel.kptr_restrict from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*kernel.kptr_restrict + replace: '#kernel.kptr_restrict' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Ensure sysctl kernel.kptr_restrict + is set + ansible.posix.sysctl: name: kernel.kptr_restrict value: '{{ sysctl_kernel_kptr_restrict_value }}' sysctl_file: /etc/sysctl.conf @@ -89040,6 +102082,10 @@ fi - reboot_required - sysctl_kernel_kptr_restrict + + + + @@ -89053,8 +102099,6 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.randomize_va_space = 2 3.1.7 - CCI-000366 - CCI-002824 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -89062,42 +102106,43 @@ To make sure that the setting is persistent, add the following line to a file in 164.310(c) 164.312(a) 164.312(e) - CIP-002-5 R1.1 - CIP-002-5 R1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 4.1 - CIP-004-6 4.2 - CIP-004-6 R2.2.3 - CIP-004-6 R2.2.4 - CIP-004-6 R2.3 - CIP-004-6 R4 - CIP-005-6 R1 - CIP-005-6 R1.1 - CIP-005-6 R1.2 - CIP-007-3 R3 - CIP-007-3 R3.1 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R8.4 - CIP-009-6 R.1.1 - CIP-009-6 R4 + CIP-002-5 R1.1 + CIP-002-5 R1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 4.1 + CIP-004-6 4.2 + CIP-004-6 R2.2.3 + CIP-004-6 R2.2.4 + CIP-004-6 R2.3 + CIP-004-6 R4 + CIP-005-6 R1 + CIP-005-6 R1.1 + CIP-005-6 R1.2 + CIP-007-3 R3 + CIP-007-3 R3.1 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R8.4 + CIP-009-6 R.1.1 + CIP-009-6 R4 SC-30 SC-30(2) CM-6(a) Req-2.2.1 - SRG-OS-000433-GPOS-00193 - SRG-OS-000480-GPOS-00227 - SRG-APP-000450-CTR-001105 + SRG-OS-000433-GPOS-00193 + SRG-OS-000480-GPOS-00227 + SRG-APP-000450-CTR-001105 R9 + 1409 3.3.1.1 3.3.1 3.3 - OL09-00-002423 - SV-271761r1091995_rule + OL09-00-002423 + SV-271761r1091995_rule Address space layout randomization (ASLR) makes it more difficult for an attacker to predict the location of attack code they have introduced into a process's address space during an attempt at exploitation. Additionally, @@ -89136,7 +102181,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.randomize_va_space # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.randomize_va_space="2" fi @@ -89189,16 +102234,12 @@ fi - reboot_required - sysctl_kernel_randomize_va_space -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Randomized Layout of Virtual Address Space - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.randomize_va_space.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002423 @@ -89217,13 +102258,71 @@ fi - reboot_required - sysctl_kernel_randomize_va_space -- name: Comment out any occurrences of kernel.randomize_va_space from config files - replace: - path: '{{ item.path }}' +- name: Enable Randomized Layout of Virtual Address Space - Find all files that contain + kernel.randomize_va_space + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.randomize_va_space\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: Enable Randomized Layout of Virtual Address Space - Find all files that set + kernel.randomize_va_space to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.randomize_va_space\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: Enable Randomized Layout of Virtual Address Space - Comment out any occurrences + of kernel.randomize_va_space from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.randomize_va_space replace: '#kernel.randomize_va_space' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002423 - NIST-800-171-3.1.7 @@ -89241,8 +102340,9 @@ fi - reboot_required - sysctl_kernel_randomize_va_space -- name: Ensure sysctl kernel.randomize_va_space is set to 2 - sysctl: +- name: Enable Randomized Layout of Virtual Address Space - Ensure sysctl kernel.randomize_va_space + is set to 2 + ansible.posix.sysctl: name: kernel.randomize_va_space value: '2' sysctl_file: /etc/sysctl.conf @@ -89266,6 +102366,10 @@ fi - reboot_required - sysctl_kernel_randomize_va_space + + + + @@ -89303,7 +102407,6 @@ on AMD-based systems. BAI10.03 BAI10.05 3.1.7 - CCI-002824 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -89316,13 +102419,13 @@ on AMD-based systems. SC-39 CM-6(a) PR.IP-1 - SRG-OS-000433-GPOS-00192 - SRG-APP-000450-CTR-001105 + SRG-OS-000433-GPOS-00192 + SRG-APP-000450-CTR-001105 2.2.1 2.2 Computers with the ability to prevent this type of code execution frequently put an option in the BIOS that will allow users to turn the feature on or off at will. - + @@ -89359,14 +102462,12 @@ default Grub2 command line for Linux operating systems. Modify the line within GRUB_CMDLINE_LINUX="... page_poison=1 ..." Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="page_poison=1" - CCI-000366 - CCI-001084 CM-6(a) - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 R8 - OL09-00-002394 - SV-271738r1092600_rule + OL09-00-002394 + SV-271738r1092600_rule Poisoning writes an arbitrary value to freed pages, so any modification or reference to that page after being freed or before being initialized will be detected and prevented. @@ -89376,15 +102477,12 @@ Also prevents leak of data and detection of corrupted memory.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "page_poison" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_poison=[^\"]*\"(.*]\s*)/\1\"page_poison=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_poison=[^\"]*\"(.*]\s*)/\1\"page_poison=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"page_poison=$expected_value\"]" >> "$KARGS_DIR/10-page_poison.toml" + echo "kargs = [\"page_poison=1\"]" >> "$KARGS_DIR/10-page_poison.toml" fi else @@ -89409,8 +102507,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="page_poison=1" +- name: Check if page_poison argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -89423,6 +102523,42 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if page_poison argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002394 + - NIST-800-53-CM-6(a) + - grub2_page_poison_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="page_poison=1" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('page_poison=1')) or ((etc_default_grub['content'] + | b64decode) is not search('page_poison=1')) + tags: + - DISA-STIG-OL09-00-002394 + - NIST-800-53-CM-6(a) + - grub2_page_poison_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "page_poison=1" @@ -89449,14 +102585,12 @@ default Grub2 command line for Linux operating systems. Modify the line within GRUB_CMDLINE_LINUX="... slub_debug= ..." Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="slub_debug=" - CCI-002824 - CCI-001084 CM-6(a) - SRG-OS-000433-GPOS-00192 - SRG-OS-000134-GPOS-00068 + SRG-OS-000433-GPOS-00192 + SRG-OS-000134-GPOS-00068 R8 - OL09-00-002390 - SV-271734r1091914_rule + OL09-00-002390 + SV-271734r1091914_rule Poisoning writes an arbitrary value to freed objects, so any modification or reference to that object after being freed or before being initialized will be detected and prevented. @@ -89468,15 +102602,14 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet - var_slub_debug_options='' -expected_value="$var_slub_debug_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "slub_debug" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slub_debug=[^\"]*\"(.*]\s*)/\1\"slub_debug=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slub_debug=[^\"]*\"(.*]\s*)/\1\"slub_debug=$var_slub_debug_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"slub_debug=$expected_value\"]" >> "$KARGS_DIR/10-slub_debug.toml" + echo "kargs = [\"slub_debug=$var_slub_debug_options\"]" >> "$KARGS_DIR/10-slub_debug.toml" fi else @@ -89506,9 +102639,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="slub_debug={{ var_slub_debug_options - }}" +- name: Check if slub_debug argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -89521,6 +102655,43 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if slub_debug argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002390 + - NIST-800-53-CM-6(a) + - grub2_slub_debug_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="slub_debug={{ + var_slub_debug_options }}" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('slub_debug=' ~ var_slub_debug_options)) or + ((etc_default_grub['content'] | b64decode) is not search('slub_debug=' ~ var_slub_debug_options)) + tags: + - DISA-STIG-OL09-00-002390 + - NIST-800-53-CM-6(a) + - grub2_slub_debug_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "slub_debug=" @@ -89536,6 +102707,30 @@ append = "slub_debug= + Secure boot configuration + Secure Boot is a protocol that enables a safe and trusted path during the Linux boot process. +It verifies that the code the firmware loads on a motherboard is the code +that the user intends for the computer to load. + +Secure Boot is part of the Unified Extensible Firmware Interface (UEFI). The protocol +defines a process that prevents the loading of unsigned drivers, boot loaders, or +kernel modules (or those with unacceptable digital signatures). When Secure Boot +is enabled, system boot loaders, the Red Hat Enterprise Linux kernel, and all +kernel modules must be cryptographically signed with a private key. +This allows them to be authenticated with the corresponding public key. + + + Ensure that Secure Boot is enabled + Ensure that Secure Boot is enabled with the mokutil command. + 1745 + By ensuring the integrity of the boot process, Secure Boot protects against rootkits, +bootkits, and other low-level malware that could compromise the system before traditional defenses activate. This helps maintain both the confidentiality and integrity of the system, ensuring that sensitive data remains protected and only trusted code is executed. + + + + + SELinux SELinux is a feature of the Linux kernel which can be @@ -89621,7 +102816,7 @@ fi - package_libselinux_installed - name: Ensure libselinux is installed - package: + ansible.builtin.package: name: libselinux state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89664,10 +102859,9 @@ version = "*" $ sudo yum install policycoreutils-python-utils - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-000210 - SV-271468r1091116_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000210 + SV-271468r1091116_rule This package is required to operate and manage an SELinux environment and its policies. It provides utilities such as semanage, audit2allow, audit2why, chcat and sandbox. # Remediation is applicable only in certain platforms @@ -89694,7 +102888,7 @@ fi - package_policycoreutils-python-utils_installed - name: Ensure policycoreutils-python-utils is installed - package: + ansible.builtin.package: name: policycoreutils-python-utils state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89736,12 +102930,10 @@ version = "*" $ sudo yum install policycoreutils - CCI-000366 - CCI-001084 - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - OL09-00-000200 - SV-271467r1091113_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + OL09-00-000200 + SV-271467r1091113_rule Security-enhanced Linux is a feature of the Linux kernel and a number of utilities with enhanced security functionality designed to add mandatory access controls to Linux. The Security-enhanced Linux kernel contains new architectural components originally @@ -89778,7 +102970,7 @@ fi - package_policycoreutils_installed - name: Ensure policycoreutils is installed - package: + ansible.builtin.package: name: policycoreutils state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89829,10 +103021,11 @@ have running on a server. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove setroubleshoot-plugins -# from the system, and may remove any packages -# that depend on setroubleshoot-plugins. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on setroubleshoot-plugins. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "setroubleshoot-plugins" ; then yum remove -y "setroubleshoot-plugins" @@ -89853,8 +103046,9 @@ fi - no_reboot_needed - package_setroubleshoot-plugins_removed -- name: Ensure setroubleshoot-plugins is removed - package: +- name: 'Uninstall setroubleshoot-plugins Package: Ensure setroubleshoot-plugins is + removed' + ansible.builtin.package: name: setroubleshoot-plugins state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89866,7 +103060,8 @@ fi - no_reboot_needed - package_setroubleshoot-plugins_removed - include remove_setroubleshoot-plugins + +include remove_setroubleshoot-plugins class remove_setroubleshoot-plugins { package { 'setroubleshoot-plugins': @@ -89875,6 +103070,7 @@ class remove_setroubleshoot-plugins { } + package --remove=setroubleshoot-plugins @@ -89900,10 +103096,11 @@ running on a server. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove setroubleshoot-server -# from the system, and may remove any packages -# that depend on setroubleshoot-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on setroubleshoot-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "setroubleshoot-server" ; then yum remove -y "setroubleshoot-server" @@ -89924,8 +103121,9 @@ fi - no_reboot_needed - package_setroubleshoot-server_removed -- name: Ensure setroubleshoot-server is removed - package: +- name: 'Uninstall setroubleshoot-server Package: Ensure setroubleshoot-server is + removed' + ansible.builtin.package: name: setroubleshoot-server state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89937,7 +103135,8 @@ fi - no_reboot_needed - package_setroubleshoot-server_removed - include remove_setroubleshoot-server + +include remove_setroubleshoot-server class remove_setroubleshoot-server { package { 'setroubleshoot-server': @@ -89946,6 +103145,7 @@ class remove_setroubleshoot-server { } + package --remove=setroubleshoot-server @@ -89972,10 +103172,11 @@ X Windows is removed or disabled. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove setroubleshoot -# from the system, and may remove any packages -# that depend on setroubleshoot. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on setroubleshoot. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "setroubleshoot" ; then yum remove -y "setroubleshoot" @@ -89996,8 +103197,8 @@ fi - no_reboot_needed - package_setroubleshoot_removed -- name: Ensure setroubleshoot is removed - package: +- name: 'Uninstall setroubleshoot Package: Ensure setroubleshoot is removed' + ansible.builtin.package: name: setroubleshoot state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90009,7 +103210,8 @@ fi - no_reboot_needed - package_setroubleshoot_removed - include remove_setroubleshoot + +include remove_setroubleshoot class remove_setroubleshoot { package { 'setroubleshoot': @@ -90018,6 +103220,7 @@ class remove_setroubleshoot { } + package --remove=setroubleshoot @@ -90026,7 +103229,8 @@ package --remove=setroubleshoot Verify Group Who Owns /etc/selinux Directory - To properly set the group owner of /etc/selinux, run the command: $ sudo chgrp root /etc/selinux + To properly set the group owner of /etc/selinux, run the command: +$ sudo chgrp root /etc/selinux R50 The ownership of the /etc/selinux directory by the root group is important @@ -90036,7 +103240,17 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/selinux/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/selinux/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90053,11 +103267,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - directory_groupowner_etc_selinux_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_selinux_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_selinux_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/selinux/ - file: + ansible.builtin.file: path: /etc/selinux/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_selinux_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -90076,7 +103321,8 @@ fi Verify User Who Owns /etc/selinux Directory - To properly set the owner of /etc/selinux, run the command: $ sudo chown root /etc/selinux + To properly set the owner of /etc/selinux, run the command: +$ sudo chown root /etc/selinux R50 The ownership of the /etc/selinux directory by the root user is important @@ -90086,7 +103332,17 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/selinux/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/selinux/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90103,11 +103359,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_selinux_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_selinux_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/selinux/ - file: + ansible.builtin.file: path: /etc/selinux/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_selinux_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -90136,7 +103405,7 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/selinux/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; +find -H /etc/selinux/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90154,7 +103423,8 @@ fi - no_reboot_needed - name: Find /etc/selinux/ file(s) - command: 'find -H /etc/selinux/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /etc/selinux/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -90169,7 +103439,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/selinux/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -90193,7 +103463,8 @@ fi Verify Group Who Owns /etc/sestatus.conf File - To properly set the group owner of /etc/sestatus.conf, run the command: $ sudo chgrp root /etc/sestatus.conf + To properly set the group owner of /etc/sestatus.conf, run the command: +$ sudo chgrp root /etc/sestatus.conf R50 The ownership of the /etc/sestatus.conf file by the root group is important @@ -90203,7 +103474,19 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp root /etc/sestatus.conf +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/sestatus.conf" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/sestatus.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90220,8 +103503,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_sestatus_conf_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_sestatus_conf_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_sestatus_conf_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/sestatus.conf - stat: + ansible.builtin.stat: path: /etc/sestatus.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90233,10 +103546,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/sestatus.conf - file: +- name: Ensure group owner on /etc/sestatus.conf + ansible.builtin.file: path: /etc/sestatus.conf - group: root + follow: false + group: '{{ file_groupowner_etc_sestatus_conf_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -90257,7 +103571,8 @@ fi Verify User Who Owns /etc/sestatus.conf File - To properly set the owner of /etc/sestatus.conf, run the command: $ sudo chown root /etc/sestatus.conf + To properly set the owner of /etc/sestatus.conf, run the command: +$ sudo chown root /etc/sestatus.conf R50 The ownership of the /etc/sestatus.conf file by the root user is important @@ -90267,7 +103582,19 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/sestatus.conf +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/sestatus.conf" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/sestatus.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90284,8 +103611,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_sestatus_conf_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_sestatus_conf_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/sestatus.conf - stat: + ansible.builtin.stat: path: /etc/sestatus.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90297,10 +103636,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/sestatus.conf - file: +- name: Ensure owner on /etc/sestatus.conf + ansible.builtin.file: path: /etc/sestatus.conf - owner: '0' + follow: false + owner: '{{ file_owner_etc_sestatus_conf_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -90349,7 +103689,7 @@ fi - no_reboot_needed - name: Test for existence /etc/sestatus.conf - stat: + ansible.builtin.stat: path: /etc/sestatus.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90362,7 +103702,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/sestatus.conf - file: + ansible.builtin.file: path: /etc/sestatus.conf mode: u-xs,g-xws,o-xwt when: @@ -90419,8 +103759,6 @@ file to prevent SELinux from being disabled at boot. MEA02.01 3.1.2 3.7.2 - CCI-000022 - CCI-000032 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -90526,16 +103864,16 @@ file to prevent SELinux from being disabled at boot. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-3 AC-3(3)(a) DE.AE-1 @@ -90776,7 +104114,6 @@ can be achieved by amending SELinux policy. 3.1.2 3.1.5 3.7.2 - CCI-000366 4.3.3.3.9 4.3.3.5.1 4.3.3.5.2 @@ -90882,9 +104219,9 @@ can be achieved by amending SELinux policy. PR.IP-3 PR.PT-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002500 - SV-271769r1092019_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002500 + SV-271769r1092019_rule If a device file carries the SELinux type device_t or unlabeled_t, then SELinux cannot properly restrict access to the device file. @@ -91033,15 +104370,15 @@ daemons as outlined above. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-7(a) CM-7(b) CM-6(a) @@ -91071,7 +104408,9 @@ the system to boot into enforcing or permissive mode: SELINUX=enforcing OR SELINUX=permissive - +Ensure that all files have correct SELinux labels by running: +fixfiles onboot +Then reboot the system. In case the SELinux is "disabled", the automated remediation will adopt a more conservative approach and set it to "permissive" in order to avoid any system disruption and give the administrator the opportunity to assess the impact and necessary efforts @@ -91098,7 +104437,6 @@ printf '%s\n' "SELINUX=permissive" >> "/etc/selinux/config" rm "/etc/selinux/config.bak" fixfiles onboot -fixfiles -f relabel else >&2 echo 'Remediation is not applicable, nothing was done' @@ -91115,11 +104453,26 @@ fi - restrict_strategy - selinux_not_disabled +- name: Ensure SELinux is Not Disabled - Check current SELinux state + ansible.builtin.command: + cmd: getenforce + register: selinux_state + check_mode: false + changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + - selinux_not_disabled + - name: Ensure SELinux is Not Disabled block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91129,7 +104482,7 @@ fi register: dupes - name: Deduplicate values from /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91137,7 +104490,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91151,6 +104504,23 @@ fi - reboot_required - restrict_strategy - selinux_not_disabled + +- name: Ensure SELinux is Not Disabled - Mark system to relabel SELinux on next boot + ansible.builtin.file: + path: /.autorelabel + state: touch + access_time: preserve + modification_time: preserve + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - selinux_state.stdout | lower != "permissive" + tags: + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + - selinux_not_disabled @@ -91200,7 +104570,6 @@ use cases. MEA02.01 3.1.2 3.7.2 - CCI-002696 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -91306,19 +104675,19 @@ use cases. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 AC-3 AC-3(3)(a) AU-9 @@ -91333,8 +104702,8 @@ use cases. PR.PT-3 PR.PT-4 FMT_MOF_EXT.1 - SRG-OS-000445-GPOS-00199 - SRG-APP-000233-CTR-000585 + SRG-OS-000445-GPOS-00199 + SRG-APP-000233-CTR-000585 R46 R64 APP.4.4.A4 @@ -91342,10 +104711,11 @@ use cases. SYS.1.6.A18 SYS.1.6.A21 A.6.SEC-OL1 + 1409 1.2.6 1.2 - OL09-00-000065 - SV-271453r1091071_rule + OL09-00-000065 + SV-271453r1091071_rule Setting the SELinux policy to targeted or a more specialized policy ensures the system will confine processes that are likely to be targeted for exploitation, such as network or system services. @@ -91356,12 +104726,11 @@ temporarily place non-production systems in permissive mo temporary cases, SELinux policies should be developed, and once work is completed, the system should be reconfigured to . - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_selinux_policy_name='' - if [ -e "/etc/selinux/config" ] ; then LC_ALL=C sed -i "/^SELINUXTYPE=/Id" "/etc/selinux/config" @@ -91381,7 +104750,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -91394,11 +104763,11 @@ fi - NIST-800-53-SC-7(21) - PCI-DSSv4-1.2 - PCI-DSSv4-1.2.6 + - configure_strategy - low_complexity - low_disruption - medium_severity - - reboot_required - - restrict_strategy + - no_reboot_needed - selinux_policytype - name: XCCDF Value var_selinux_policy_name # promote to variable set_fact: @@ -91410,7 +104779,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUXTYPE= @@ -91420,7 +104789,7 @@ fi register: dupes - name: Deduplicate values from /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUXTYPE= @@ -91428,7 +104797,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUXTYPE= @@ -91445,11 +104814,11 @@ fi - NIST-800-53-SC-7(21) - PCI-DSSv4-1.2 - PCI-DSSv4-1.2.6 + - configure_strategy - low_complexity - low_disruption - medium_severity - - reboot_required - - restrict_strategy + - no_reboot_needed - selinux_policytype @@ -91467,7 +104836,9 @@ system boot time. In the file /etc/selinux/config, add o following line to configure the system to boot into enforcing mode: SELINUX= - +Ensure that all files have correct SELinux labels by running: +fixfiles onboot +Then reboot the system. 1 11 12 @@ -91498,8 +104869,6 @@ following line to configure the system to boot into enforcing mode: MEA02.01 3.1.2 3.7.2 - CCI-002696 - CCI-001084 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -91605,19 +104974,19 @@ following line to configure the system to boot into enforcing mode: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 AC-3 AC-3(3)(a) AU-9 @@ -91632,8 +105001,8 @@ following line to configure the system to boot into enforcing mode: PR.PT-3 PR.PT-4 FMT_MOF_EXT.1 - SRG-OS-000445-GPOS-00199 - SRG-OS-000134-GPOS-00068 + SRG-OS-000445-GPOS-00199 + SRG-OS-000134-GPOS-00068 R37 R79 APP.4.4.A4 @@ -91641,10 +105010,11 @@ following line to configure the system to boot into enforcing mode: SYS.1.6.A18 SYS.1.6.A21 A.6.SEC-OL1 + 1409 1.2.6 1.2 - OL09-00-000060 - SV-271452r1091068_rule + OL09-00-000060 + SV-271452r1091068_rule Setting the SELinux state to enforcing ensures SELinux is able to confine potentially compromised processes to the security policy, which is designed to prevent them from causing damage to the system or further elevating their @@ -91671,7 +105041,6 @@ printf '%s\n' "SELINUX=$var_selinux_state" >> "/etc/selinux/config" rm "/etc/selinux/config.bak" fixfiles onboot -fixfiles -f relabel else >&2 echo 'Remediation is not applicable, nothing was done' @@ -91702,11 +105071,35 @@ fi tags: - always +- name: Ensure SELinux State is Enforcing - Check current SELinux state + ansible.builtin.command: + cmd: getenforce + register: selinux_state + check_mode: false + changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000060 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - selinux_state + - name: Ensure SELinux State is Enforcing block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91716,7 +105109,7 @@ fi register: dupes - name: Deduplicate values from /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91724,7 +105117,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91747,6 +105140,33 @@ fi - no_reboot_needed - restrict_strategy - selinux_state + +- name: Ensure SELinux State is Enforcing - Mark system to relabel SELinux on next + boot + ansible.builtin.file: + path: /.autorelabel + state: touch + access_time: preserve + modification_time: preserve + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - selinux_state.stdout | lower != var_selinux_state + tags: + - DISA-STIG-OL09-00-000060 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - selinux_state @@ -91760,7 +105180,7 @@ fi SELinux - Booleans Enable or Disable runtime customization of SELinux system policies without having to reload or recompile the SELinux policy. - + auditadm_exec_content SELinux Boolean default - Default SELinux boolean setting. @@ -91870,30 +105290,23 @@ To enable the auditadm_exec_content SELinux boolean, run 80424-5 0582 - 0584 - 05885 - 0586 0846 - 0957 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_auditadm_exec_content='' - setsebool -P auditadm_exec_content $var_auditadm_exec_content - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P auditadm_exec_content $var_auditadm_exec_content else >&2 echo 'Remediation is not applicable, nothing was done' @@ -91913,10 +105326,15 @@ fi - name: Enable the auditadm_exec_content SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-80424-5 - enable_strategy @@ -91933,13 +105351,16 @@ fi - name: Enable the auditadm_exec_content SELinux Boolean - Set SELinux Boolean auditadm_exec_content Accordingly - seboolean: + ansible.posix.seboolean: name: auditadm_exec_content state: '{{ var_auditadm_exec_content }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - NIST-800-171-80424-5 - enable_strategy @@ -91949,6 +105370,11 @@ fi - no_reboot_needed - sebool_auditadm_exec_content + + + + + @@ -91968,7 +105394,6 @@ To disable the authlogin_nsswitch_use_ldap SELinux boolea 3.7.2 0421 0422 - 0431 0974 1173 1401 @@ -91982,23 +105407,20 @@ To disable the authlogin_nsswitch_use_ldap SELinux boolea 1561 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_authlogin_nsswitch_use_ldap='' - setsebool -P authlogin_nsswitch_use_ldap $var_authlogin_nsswitch_use_ldap - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P authlogin_nsswitch_use_ldap $var_authlogin_nsswitch_use_ldap else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92018,10 +105440,15 @@ fi - name: Disable the authlogin_nsswitch_use_ldap SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92038,13 +105465,16 @@ fi - name: Disable the authlogin_nsswitch_use_ldap SELinux Boolean - Set SELinux Boolean authlogin_nsswitch_use_ldap Accordingly - seboolean: + ansible.posix.seboolean: name: authlogin_nsswitch_use_ldap state: '{{ var_authlogin_nsswitch_use_ldap }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92054,6 +105484,11 @@ fi - no_reboot_needed - sebool_authlogin_nsswitch_use_ldap + + + + + @@ -92073,7 +105508,6 @@ To disable the authlogin_radius SELinux boolean, run the 3.7.2 0421 0422 - 0431 0974 1173 1401 @@ -92087,23 +105521,20 @@ To disable the authlogin_radius SELinux boolean, run the 1561 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_authlogin_radius='' - setsebool -P authlogin_radius $var_authlogin_radius - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P authlogin_radius $var_authlogin_radius else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92123,10 +105554,15 @@ fi - name: Disable the authlogin_radius SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92143,13 +105579,16 @@ fi - name: Disable the authlogin_radius SELinux Boolean - Set SELinux Boolean authlogin_radius Accordingly - seboolean: + ansible.posix.seboolean: name: authlogin_radius state: '{{ var_authlogin_radius }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92159,6 +105598,11 @@ fi - no_reboot_needed - sebool_authlogin_radius + + + + + @@ -92183,6 +105627,11 @@ boolean in production systems. R48 Allowing user domain applications to map a memory region as both writable and executable makes them more susceptible to data execution attacks. + + + + + @@ -92205,23 +105654,20 @@ To enable the kerberos_enabled SELinux boolean, run the f 1402 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_kerberos_enabled='' - setsebool -P kerberos_enabled $var_kerberos_enabled - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P kerberos_enabled $var_kerberos_enabled else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92239,10 +105685,15 @@ fi - sebool_kerberos_enabled - name: Enable the kerberos_enabled SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92258,13 +105709,16 @@ fi - name: Enable the kerberos_enabled SELinux Boolean - Set SELinux Boolean kerberos_enabled Accordingly - seboolean: + ansible.posix.seboolean: name: kerberos_enabled state: '{{ var_kerberos_enabled }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92273,6 +105727,11 @@ fi - no_reboot_needed - sebool_kerberos_enabled + + + + + @@ -92293,23 +105752,20 @@ To set the polyinstantiation_enabled SELinux boolean, run R55 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_polyinstantiation_enabled='' - setsebool -P polyinstantiation_enabled $var_polyinstantiation_enabled - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P polyinstantiation_enabled $var_polyinstantiation_enabled else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92328,10 +105784,15 @@ fi - name: Configure the polyinstantiation_enabled SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92347,13 +105808,16 @@ fi - name: Configure the polyinstantiation_enabled SELinux Boolean - Set SELinux Boolean polyinstantiation_enabled Accordingly - seboolean: + ansible.posix.seboolean: name: polyinstantiation_enabled state: '{{ var_polyinstantiation_enabled }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92362,6 +105826,11 @@ fi - no_reboot_needed - sebool_polyinstantiation_enabled + + + + + @@ -92382,7 +105851,7 @@ To set the secure_mode_insmod SELinux boolean, run the fo R48 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_secure_mode_insmod='' @@ -92417,7 +105886,12 @@ fi ansible.builtin.package: name: libsemanage-python state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92432,7 +105906,12 @@ fi name: secure_mode_insmod state: '{{ var_secure_mode_insmod }}' persistent: true - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92448,7 +105927,12 @@ fi dest: /etc/modules-load.d/vfat.conf regexp: ^\s*\bvfat\b line: vfat - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92460,7 +105944,12 @@ fi - name: Configure the secure_mode_insmod SELinux Boolean - Regenerate initramfs ansible.builtin.command: cmd: dracut -f --regenerate-all - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92469,6 +105958,11 @@ fi - no_reboot_needed - sebool_secure_mode_insmod + + + + + @@ -92496,23 +105990,20 @@ To disable the selinuxuser_execheap SELinux boolean, run R48 Disabling code execution from the heap blocks buffer overflow attacks. # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_selinuxuser_execheap='' - setsebool -P selinuxuser_execheap $var_selinuxuser_execheap - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P selinuxuser_execheap $var_selinuxuser_execheap else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92531,10 +106022,15 @@ fi - name: Disable the selinuxuser_execheap SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92550,13 +106046,16 @@ fi - name: Disable the selinuxuser_execheap SELinux Boolean - Set SELinux Boolean selinuxuser_execheap Accordingly - seboolean: + ansible.posix.seboolean: name: selinuxuser_execheap state: '{{ var_selinuxuser_execheap }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92565,6 +106064,11 @@ fi - no_reboot_needed - sebool_selinuxuser_execheap + + + + + @@ -92590,23 +106094,20 @@ To enable the selinuxuser_execmod SELinux boolean, run th 164.312(e) # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_selinuxuser_execmod='' - setsebool -P selinuxuser_execmod $var_selinuxuser_execmod - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P selinuxuser_execmod $var_selinuxuser_execmod else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92625,10 +106126,15 @@ fi - name: Enable the selinuxuser_execmod SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92644,13 +106150,16 @@ fi - name: Enable the selinuxuser_execmod SELinux Boolean - Set SELinux Boolean selinuxuser_execmod Accordingly - seboolean: + ansible.posix.seboolean: name: selinuxuser_execmod state: '{{ var_selinuxuser_execmod }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92659,6 +106168,11 @@ fi - no_reboot_needed - sebool_selinuxuser_execmod + + + + + @@ -92686,23 +106200,20 @@ To disable the selinuxuser_execstack SELinux boolean, run R48 Disabling code execution from the stack blocks buffer overflow attacks. # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_selinuxuser_execstack='' - setsebool -P selinuxuser_execstack $var_selinuxuser_execstack - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P selinuxuser_execstack $var_selinuxuser_execstack else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92721,10 +106232,15 @@ fi - name: Disable the selinuxuser_execstack SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92740,13 +106256,16 @@ fi - name: Disable the selinuxuser_execstack SELinux Boolean - Set SELinux Boolean selinuxuser_execstack Accordingly - seboolean: + ansible.posix.seboolean: name: selinuxuser_execstack state: '{{ var_selinuxuser_execstack }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92755,6 +106274,11 @@ fi - no_reboot_needed - sebool_selinuxuser_execstack + + + + + @@ -92771,9 +106295,7 @@ If this setting is enabled, it should be disabled. To disable the ssh_sysadm_login SELinux boolean, run the following command: $ sudo setsebool -P ssh_sysadm_login off - CCI-002165 - CCI-002235 - SRG-OS-000324-GPOS-00125 + SRG-OS-000324-GPOS-00125 R48 Preventing non-privileged users from executing privileged functions mitigates the risk that unauthorized individuals or processes may gain unnecessary access @@ -92786,23 +106308,20 @@ authorizations. Circumventing intrusion detection and prevention mechanisms or malicious code protection mechanisms are examples of privileged functions that require protection from non-privileged users. # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to setsebool command to avoid the issue with the command not being +# found. var_ssh_sysadm_login='' - setsebool -P ssh_sysadm_login $var_ssh_sysadm_login - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P ssh_sysadm_login $var_ssh_sysadm_login else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92821,10 +106340,15 @@ fi - name: Disable the ssh_sysadm_login SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92840,13 +106364,16 @@ fi - name: Disable the ssh_sysadm_login SELinux Boolean - Set SELinux Boolean ssh_sysadm_login Accordingly - seboolean: + ansible.posix.seboolean: name: ssh_sysadm_login state: '{{ var_ssh_sysadm_login }}' persistent: true when: + - ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages + and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild" + or ansible_facts.selinux.status != "disabled" ) - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92855,6 +106382,11 @@ fi - no_reboot_needed - sebool_ssh_sysadm_login + + + + + @@ -92993,7 +106525,6 @@ The avahi-daemon service can be disabled with the followi DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -93050,6 +106581,7 @@ The avahi-daemon service can be disabled with the followi CM-6(a) PR.IP-1 PR.PT-3 + 1409 2.2.4 2.2 Because the Avahi daemon service keeps an open network @@ -93098,93 +106630,54 @@ fi - no_reboot_needed - service_avahi-daemon_disabled -- name: Disable Avahi Server Software - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Avahi Server Software - Disable service avahi-daemon + block: + + - name: Disable Avahi Server Software - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Avahi Server Software - Ensure avahi-daemon.service is Masked + ansible.builtin.systemd: + name: avahi-daemon.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("avahi-daemon.service", multiline=True) + + - name: Unit Socket Exists - avahi-daemon.socket + ansible.builtin.command: systemctl -q list-unit-files avahi-daemon.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Avahi Server Software - Disable Socket avahi-daemon + ansible.builtin.systemd: + name: avahi-daemon.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("avahi-daemon.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + - special_service_block when: ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Disable Avahi Server Software - Ensure avahi-daemon.service is Masked - ansible.builtin.systemd: - name: avahi-daemon.service - state: stopped - enabled: false - masked: true - when: - - ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("avahi-daemon.service", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Unit Socket Exists - avahi-daemon.socket - ansible.builtin.command: systemctl -q list-unit-files avahi-daemon.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Disable Avahi Server Software - Disable Socket avahi-daemon - ansible.builtin.systemd: - name: avahi-daemon.socket - enabled: false - state: stopped - masked: true - when: - - ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("avahi-daemon.socket", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled include disable_avahi-daemon @@ -93199,6 +106692,10 @@ class disable_avahi-daemon { [customizations.services] masked = ["avahi-daemon"] + + + + @@ -93242,7 +106739,6 @@ The kdump service can be disabled with the following comm DSS05.03 DSS05.05 DSS06.06 - CCI-000366 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -93324,10 +106820,10 @@ The kdump service can be disabled with the following comm PR.PT-3 PR.PT-4 FMT_SMF_EXT.1.1 - SRG-OS-000269-GPOS-00103 - SRG-OS-000480-GPOS-00227 - OL09-00-002385 - SV-271733r1092598_rule + SRG-OS-000269-GPOS-00103 + SRG-OS-000480-GPOS-00227 + OL09-00-002385 + SV-271733r1092598_rule Kernel core dumps may contain the full contents of system memory at the time of the crash. Kernel core dumps consume a considerable amount of disk space and may result in denial of service by exhausting the available space @@ -93374,86 +106870,52 @@ fi - no_reboot_needed - service_kdump_disabled -- name: Disable KDump Kernel Crash Analyzer (kdump) - Collect systemd Services Present - in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable KDump Kernel Crash Analyzer (kdump) - Disable service kdump + block: + + - name: Disable KDump Kernel Crash Analyzer (kdump) - Collect systemd Services Present + in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable KDump Kernel Crash Analyzer (kdump) - Ensure kdump.service is Masked + ansible.builtin.systemd: + name: kdump.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("kdump.service", multiline=True) + + - name: Unit Socket Exists - kdump.socket + ansible.builtin.command: systemctl -q list-unit-files kdump.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable KDump Kernel Crash Analyzer (kdump) - Disable Socket kdump + ansible.builtin.systemd: + name: kdump.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("kdump.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Disable KDump Kernel Crash Analyzer (kdump) - Ensure kdump.service is Masked - ansible.builtin.systemd: - name: kdump.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("kdump.service", multiline=True) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Unit Socket Exists - kdump.socket - ansible.builtin.command: systemctl -q list-unit-files kdump.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Disable KDump Kernel Crash Analyzer (kdump) - Disable Socket kdump - ansible.builtin.systemd: - name: kdump.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("kdump.socket", multiline=True) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled include disable_kdump @@ -93471,6 +106933,10 @@ kdump --disable [customizations.services] masked = ["kdump"] + + + + @@ -93499,7 +106965,6 @@ The oddjobd service can be disabled with the following co DSS05.02 DSS05.05 DSS06.06 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -93600,82 +107065,51 @@ fi - no_reboot_needed - service_oddjobd_disabled -- name: Disable Odd Job Daemon (oddjobd) - Collect systemd Services Present in the - System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Odd Job Daemon (oddjobd) - Disable service oddjobd + block: + + - name: Disable Odd Job Daemon (oddjobd) - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Odd Job Daemon (oddjobd) - Ensure oddjobd.service is Masked + ansible.builtin.systemd: + name: oddjobd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("oddjobd.service", multiline=True) + + - name: Unit Socket Exists - oddjobd.socket + ansible.builtin.command: systemctl -q list-unit-files oddjobd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Odd Job Daemon (oddjobd) - Disable Socket oddjobd + ansible.builtin.systemd: + name: oddjobd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("oddjobd.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Disable Odd Job Daemon (oddjobd) - Ensure oddjobd.service is Masked - ansible.builtin.systemd: - name: oddjobd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("oddjobd.service", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Unit Socket Exists - oddjobd.socket - ansible.builtin.command: systemctl -q list-unit-files oddjobd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Disable Odd Job Daemon (oddjobd) - Disable Socket oddjobd - ansible.builtin.systemd: - name: oddjobd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("oddjobd.socket", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled include disable_oddjobd @@ -93690,6 +107124,10 @@ class disable_oddjobd { [customizations.services] masked = ["oddjobd"] + + + + @@ -93736,7 +107174,6 @@ The rdisc service can be disabled with the following comm DSS05.07 DSS06.02 DSS06.06 - CCI-000382 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -93885,87 +107322,53 @@ fi - no_reboot_needed - service_rdisc_disabled -- name: Disable Network Router Discovery Daemon (rdisc) - Collect systemd Services - Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Network Router Discovery Daemon (rdisc) - Disable service rdisc + block: + + - name: Disable Network Router Discovery Daemon (rdisc) - Collect systemd Services + Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Network Router Discovery Daemon (rdisc) - Ensure rdisc.service is + Masked + ansible.builtin.systemd: + name: rdisc.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("rdisc.service", multiline=True) + + - name: Unit Socket Exists - rdisc.socket + ansible.builtin.command: systemctl -q list-unit-files rdisc.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Network Router Discovery Daemon (rdisc) - Disable Socket rdisc + ansible.builtin.systemd: + name: rdisc.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("rdisc.socket", multiline=True) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Disable Network Router Discovery Daemon (rdisc) - Ensure rdisc.service is - Masked - ansible.builtin.systemd: - name: rdisc.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("rdisc.service", multiline=True) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Unit Socket Exists - rdisc.socket - ansible.builtin.command: systemctl -q list-unit-files rdisc.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Disable Network Router Discovery Daemon (rdisc) - Disable Socket rdisc - ansible.builtin.systemd: - name: rdisc.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("rdisc.socket", multiline=True) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled include disable_rdisc @@ -93980,6 +107383,10 @@ class disable_rdisc { [customizations.services] masked = ["rdisc"] + + + + @@ -94010,7 +107417,6 @@ configured defensively. DSS05.02 DSS05.05 DSS06.06 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -94071,7 +107477,7 @@ configured defensively. CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 The cron service allow periodic job execution, needed for almost all administrative tasks and services (software update, log rotating, etc.). Access to cron service should be restricted to administrative accounts only. @@ -94101,7 +107507,7 @@ fi - package_cron_installed - name: Ensure cronie is installed - package: + ansible.builtin.package: name: cronie state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -94251,7 +107657,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable cron Service - Enable Service crond @@ -94262,7 +107668,6 @@ fi masked: false when: - '"cronie" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - enable_strategy @@ -94271,6 +107676,8 @@ fi - medium_severity - no_reboot_needed - service_crond_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_crond @@ -94285,6 +107692,10 @@ class enable_crond { [customizations.services] enabled = ["crond"] + + + + @@ -94314,7 +107725,6 @@ The atd service can be disabled with the following comman DSS05.02 DSS05.05 DSS06.06 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -94414,81 +107824,50 @@ fi - no_reboot_needed - service_atd_disabled -- name: Disable At Service (atd) - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable At Service (atd) - Disable service atd + block: + + - name: Disable At Service (atd) - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable At Service (atd) - Ensure atd.service is Masked + ansible.builtin.systemd: + name: atd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("atd.service", multiline=True) + + - name: Unit Socket Exists - atd.socket + ansible.builtin.command: systemctl -q list-unit-files atd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable At Service (atd) - Disable Socket atd + ansible.builtin.systemd: + name: atd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("atd.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Disable At Service (atd) - Ensure atd.service is Masked - ansible.builtin.systemd: - name: atd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("atd.service", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Unit Socket Exists - atd.socket - ansible.builtin.command: systemctl -q list-unit-files atd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Disable At Service (atd) - Disable Socket atd - ansible.builtin.systemd: - name: atd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("atd.socket", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled include disable_atd @@ -94503,6 +107882,10 @@ class disable_atd { [customizations.services] masked = ["atd"] + + + + @@ -94514,7 +107897,8 @@ masked = ["atd"] Verify Group Who Owns cron.d To properly set the group owner of /etc/cron.d, run the command: -$ sudo chgrp root /etc/cron.d + + $ sudo chgrp root /etc/cron.d 12 13 @@ -94528,7 +107912,6 @@ To properly set the group owner of /etc/cron.d, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94559,18 +107942,28 @@ To properly set the group owner of /etc/cron.d, run the c AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.d/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.d/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94592,11 +107985,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_d_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_d_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.d/ - file: + ansible.builtin.file: path: /etc/cron.d/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_d_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -94622,7 +108033,8 @@ fi Verify Group Who Owns cron.daily To properly set the group owner of /etc/cron.daily, run the command: -$ sudo chgrp root /etc/cron.daily + + $ sudo chgrp root /etc/cron.daily 12 13 @@ -94636,7 +108048,6 @@ To properly set the group owner of /etc/cron.daily, run t DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94667,18 +108078,28 @@ To properly set the group owner of /etc/cron.daily, run t AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.daily/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94700,11 +108121,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_daily_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_daily_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.daily/ - file: + ansible.builtin.file: path: /etc/cron.daily/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_daily_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -94730,20 +108169,32 @@ fi Verify Group Who Owns cron.deny To properly set the group owner of /etc/cron.deny, run the command: -$ sudo chgrp root /etc/cron.deny + + $ sudo chgrp root /etc/cron.deny - CCI-000366 CM-6 b - SRG-OS-000480-GPOS-00227 - OL09-00-002581 - SV-271828r1092196_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/cron.deny +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/cron.deny" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/cron.deny +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94762,8 +108213,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_deny_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_deny_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-CM-6 b + - configure_strategy + - file_groupowner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.deny - stat: + ansible.builtin.stat: path: /etc/cron.deny register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -94777,10 +108242,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/cron.deny - file: +- name: Ensure group owner on /etc/cron.deny + ansible.builtin.file: path: /etc/cron.deny - group: '0' + follow: false + group: '{{ file_groupowner_cron_deny_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -94805,7 +108271,8 @@ fi Verify Group Who Owns cron.hourly To properly set the group owner of /etc/cron.hourly, run the command: -$ sudo chgrp root /etc/cron.hourly + + $ sudo chgrp root /etc/cron.hourly 12 13 @@ -94819,7 +108286,6 @@ To properly set the group owner of /etc/cron.hourly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94850,18 +108316,28 @@ To properly set the group owner of /etc/cron.hourly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.hourly/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94883,11 +108359,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_hourly_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_hourly_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.hourly/ - file: + ansible.builtin.file: path: /etc/cron.hourly/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_hourly_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -94913,7 +108407,8 @@ fi Verify Group Who Owns cron.monthly To properly set the group owner of /etc/cron.monthly, run the command: -$ sudo chgrp root /etc/cron.monthly + + $ sudo chgrp root /etc/cron.monthly 12 13 @@ -94927,7 +108422,6 @@ To properly set the group owner of /etc/cron.monthly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94958,18 +108452,28 @@ To properly set the group owner of /etc/cron.monthly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.monthly/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94991,11 +108495,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_monthly_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_monthly_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.monthly/ - file: + ansible.builtin.file: path: /etc/cron.monthly/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_monthly_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -95021,7 +108543,8 @@ fi Verify Group Who Owns cron.weekly To properly set the group owner of /etc/cron.weekly, run the command: -$ sudo chgrp root /etc/cron.weekly + + $ sudo chgrp root /etc/cron.weekly 12 13 @@ -95035,7 +108558,6 @@ To properly set the group owner of /etc/cron.weekly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95066,18 +108588,28 @@ To properly set the group owner of /etc/cron.weekly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.weekly/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95099,11 +108631,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_weekly_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_weekly_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.weekly/ - file: + ansible.builtin.file: path: /etc/cron.weekly/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_weekly_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -95129,7 +108679,8 @@ fi Verify Group Who Owns Crontab To properly set the group owner of /etc/crontab, run the command: -$ sudo chgrp root /etc/crontab + + $ sudo chgrp root /etc/crontab 12 13 @@ -95143,7 +108694,6 @@ To properly set the group owner of /etc/crontab, run the DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95174,18 +108724,30 @@ To properly set the group owner of /etc/crontab, run the AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/crontab +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/crontab" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/crontab +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95207,8 +108769,25 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_crontab_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_crontab_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/crontab - stat: + ansible.builtin.stat: path: /etc/crontab register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -95225,10 +108804,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/crontab - file: +- name: Ensure group owner on /etc/crontab + ansible.builtin.file: path: /etc/crontab - group: '0' + follow: false + group: '{{ file_groupowner_crontab_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -95256,7 +108836,8 @@ fi Verify Owner on cron.d To properly set the owner of /etc/cron.d, run the command: -$ sudo chown root /etc/cron.d + + $ sudo chown root /etc/cron.d 12 13 @@ -95270,7 +108851,6 @@ To properly set the owner of /etc/cron.d, run the command DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95301,18 +108881,28 @@ To properly set the owner of /etc/cron.d, run the command AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95334,11 +108924,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_d_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_d_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.d/ - file: + ansible.builtin.file: path: /etc/cron.d/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_d_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95364,7 +108972,8 @@ fi Verify Owner on cron.daily To properly set the owner of /etc/cron.daily, run the command: -$ sudo chown root /etc/cron.daily + + $ sudo chown root /etc/cron.daily 12 13 @@ -95378,7 +108987,6 @@ To properly set the owner of /etc/cron.daily, run the com DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95409,18 +109017,28 @@ To properly set the owner of /etc/cron.daily, run the com AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.daily/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95442,11 +109060,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_daily_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_daily_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.daily/ - file: + ansible.builtin.file: path: /etc/cron.daily/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_daily_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95472,20 +109108,32 @@ fi Verify Owner on cron.deny To properly set the owner of /etc/cron.deny, run the command: -$ sudo chown root /etc/cron.deny + + $ sudo chown root /etc/cron.deny - CCI-000366 CM-6 b - SRG-OS-000480-GPOS-00227 - OL09-00-002582 - SV-271829r1092199_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/cron.deny +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/cron.deny" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/cron.deny +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95504,8 +109152,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_deny_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_deny_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-CM-6 b + - configure_strategy + - file_owner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.deny - stat: + ansible.builtin.stat: path: /etc/cron.deny register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -95519,10 +109181,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/cron.deny - file: +- name: Ensure owner on /etc/cron.deny + ansible.builtin.file: path: /etc/cron.deny - owner: '0' + follow: false + owner: '{{ file_owner_cron_deny_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -95547,7 +109210,8 @@ fi Verify Owner on cron.hourly To properly set the owner of /etc/cron.hourly, run the command: -$ sudo chown root /etc/cron.hourly + + $ sudo chown root /etc/cron.hourly 12 13 @@ -95561,7 +109225,6 @@ To properly set the owner of /etc/cron.hourly, run the co DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95592,18 +109255,28 @@ To properly set the owner of /etc/cron.hourly, run the co AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.hourly/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95625,11 +109298,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_hourly_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_hourly_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.hourly/ - file: + ansible.builtin.file: path: /etc/cron.hourly/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_hourly_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95655,7 +109346,8 @@ fi Verify Owner on cron.monthly To properly set the owner of /etc/cron.monthly, run the command: -$ sudo chown root /etc/cron.monthly + + $ sudo chown root /etc/cron.monthly 12 13 @@ -95669,7 +109361,6 @@ To properly set the owner of /etc/cron.monthly, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95700,18 +109391,28 @@ To properly set the owner of /etc/cron.monthly, run the c AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.monthly/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95733,11 +109434,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_monthly_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_monthly_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.monthly/ - file: + ansible.builtin.file: path: /etc/cron.monthly/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_monthly_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95763,7 +109482,8 @@ fi Verify Owner on cron.weekly To properly set the owner of /etc/cron.weekly, run the command: -$ sudo chown root /etc/cron.weekly + + $ sudo chown root /etc/cron.weekly 12 13 @@ -95777,7 +109497,6 @@ To properly set the owner of /etc/cron.weekly, run the co DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95808,18 +109527,28 @@ To properly set the owner of /etc/cron.weekly, run the co AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.weekly/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95841,11 +109570,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_weekly_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_weekly_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.weekly/ - file: + ansible.builtin.file: path: /etc/cron.weekly/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_weekly_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95871,7 +109618,8 @@ fi Verify Owner on crontab To properly set the owner of /etc/crontab, run the command: -$ sudo chown root /etc/crontab + + $ sudo chown root /etc/crontab 12 13 @@ -95885,7 +109633,6 @@ To properly set the owner of /etc/crontab, run the comman DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95916,18 +109663,30 @@ To properly set the owner of /etc/crontab, run the comman AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/crontab +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/crontab" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/crontab +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95949,8 +109708,25 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_crontab_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_crontab_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/crontab - stat: + ansible.builtin.stat: path: /etc/crontab register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -95967,10 +109743,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/crontab - file: +- name: Ensure owner on /etc/crontab + ansible.builtin.file: path: /etc/crontab - owner: '0' + follow: false + owner: '{{ file_owner_crontab_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -96012,7 +109789,6 @@ To properly set the permissions of /etc/cron.d, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96043,18 +109819,18 @@ To properly set the permissions of /etc/cron.d, run the c AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96077,7 +109853,8 @@ fi - no_reboot_needed - name: Find /etc/cron.d/ file(s) - command: 'find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/cron.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -96097,7 +109874,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96142,7 +109919,6 @@ To properly set the permissions of /etc/cron.daily, run t DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96173,18 +109949,18 @@ To properly set the permissions of /etc/cron.daily, run t AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.daily/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96207,7 +109983,8 @@ fi - no_reboot_needed - name: Find /etc/cron.daily/ file(s) - command: 'find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/cron.daily/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -96227,7 +110004,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.daily/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96272,7 +110049,6 @@ To properly set the permissions of /etc/cron.hourly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96303,18 +110079,18 @@ To properly set the permissions of /etc/cron.hourly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.hourly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96337,7 +110113,7 @@ fi - no_reboot_needed - name: Find /etc/cron.hourly/ file(s) - command: 'find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + ansible.builtin.command: 'find -P /etc/cron.hourly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d ' register: files_found changed_when: false @@ -96358,7 +110134,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.hourly/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96403,7 +110179,6 @@ To properly set the permissions of /etc/cron.monthly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96434,18 +110209,18 @@ To properly set the permissions of /etc/cron.monthly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.monthly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96468,7 +110243,7 @@ fi - no_reboot_needed - name: Find /etc/cron.monthly/ file(s) - command: 'find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + ansible.builtin.command: 'find -P /etc/cron.monthly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d ' register: files_found changed_when: false @@ -96489,7 +110264,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.monthly/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96534,7 +110309,6 @@ To properly set the permissions of /etc/cron.weekly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96565,18 +110339,18 @@ To properly set the permissions of /etc/cron.weekly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.weekly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96599,7 +110373,7 @@ fi - no_reboot_needed - name: Find /etc/cron.weekly/ file(s) - command: 'find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + ansible.builtin.command: 'find -P /etc/cron.weekly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d ' register: files_found changed_when: false @@ -96620,7 +110394,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.weekly/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96665,7 +110439,6 @@ To properly set the permissions of /etc/crontab, run the DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96696,11 +110469,11 @@ To properly set the permissions of /etc/crontab, run the AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002583 - SV-271830r1092202_rule + OL09-00-002583 + SV-271830r1092202_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. @@ -96730,7 +110503,7 @@ fi - no_reboot_needed - name: Test for existence /etc/crontab - stat: + ansible.builtin.stat: path: /etc/crontab register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96748,7 +110521,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crontab - file: + ansible.builtin.file: path: /etc/crontab mode: u-xs,g-xwrs,o-xwrt when: @@ -96827,8 +110600,8 @@ fi - medium_severity - no_reboot_needed -- name: Remove /etc/at.deny - file: +- name: Ensure that /etc/at.deny does not exist - Remove /etc/at.deny + ansible.builtin.file: path: /etc/at.deny state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96881,8 +110654,8 @@ fi - medium_severity - no_reboot_needed -- name: Remove /etc/cron.deny - file: +- name: Ensure that /etc/cron.deny does not exist - Remove /etc/cron.deny + ansible.builtin.file: path: /etc/cron.deny state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96908,7 +110681,8 @@ fi If /etc/at.allow exists, it must be group-owned by root. To properly set the group owner of /etc/at.allow, run the command: -$ sudo chgrp root /etc/at.allow + + $ sudo chgrp root /etc/at.allow 2.2.6 2.2 @@ -96917,7 +110691,19 @@ unauthorized user to view or edit sensitive information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/at.allow +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/at.allow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/at.allow +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96936,8 +110722,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_at_allow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_at_allow_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/at.allow - stat: + ansible.builtin.stat: path: /etc/at.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96951,10 +110751,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/at.allow - file: +- name: Ensure group owner on /etc/at.allow + ansible.builtin.file: path: /etc/at.allow - group: '0' + follow: false + group: '{{ file_groupowner_at_allow_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -96980,7 +110781,8 @@ fi If /etc/cron.allow exists, it must be group-owned by root. To properly set the group owner of /etc/cron.allow, run the command: -$ sudo chgrp root /etc/cron.allow + + $ sudo chgrp root /etc/cron.allow 12 13 @@ -96994,7 +110796,6 @@ To properly set the group owner of /etc/cron.allow, run t DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -97025,7 +110826,7 @@ To properly set the group owner of /etc/cron.allow, run t AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 If the owner of the cron.allow file is not set to root, the possibility exists for an @@ -97033,7 +110834,19 @@ unauthorized user to view or edit sensitive information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/cron.allow +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/cron.allow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/cron.allow +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -97054,8 +110867,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_allow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_allow_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.allow - stat: + ansible.builtin.stat: path: /etc/cron.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97071,10 +110900,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/cron.allow - file: +- name: Ensure group owner on /etc/cron.allow + ansible.builtin.file: path: /etc/cron.allow - group: '0' + follow: false + group: '{{ file_groupowner_cron_allow_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -97102,7 +110932,8 @@ fi If /etc/cron.allow exists, it must be owned by root. To properly set the owner of /etc/cron.allow, run the command: -$ sudo chown root /etc/cron.allow + + $ sudo chown root /etc/cron.allow 12 13 @@ -97116,7 +110947,6 @@ To properly set the owner of /etc/cron.allow, run the com DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -97147,7 +110977,7 @@ To properly set the owner of /etc/cron.allow, run the com AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 If the owner of the cron.allow file is not set to root, the possibility exists for an @@ -97155,7 +110985,19 @@ unauthorized user to view or edit sensitive information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/cron.allow +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/cron.allow" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/cron.allow +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -97176,8 +111018,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_allow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_allow_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.allow - stat: + ansible.builtin.stat: path: /etc/cron.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97193,10 +111051,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/cron.allow - file: +- name: Ensure owner on /etc/cron.allow + ansible.builtin.file: path: /etc/cron.allow - owner: '0' + follow: false + owner: '{{ file_owner_cron_allow_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -97255,7 +111114,7 @@ fi - no_reboot_needed - name: Test for existence /etc/at.allow - stat: + ansible.builtin.stat: path: /etc/at.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97270,7 +111129,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/at.allow - file: + ansible.builtin.file: path: /etc/at.allow mode: u-xs,g-xws,o-xwrt when: @@ -97302,8 +111161,7 @@ or more restrictive. To properly set the permissions of /etc/cron.allow, run the command: $ sudo chmod 0640 /etc/cron.allow - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 If the permissions of the cron.allow file are not set to 0640 or more restrictive, @@ -97331,7 +111189,7 @@ fi - no_reboot_needed - name: Test for existence /etc/cron.allow - stat: + ansible.builtin.stat: path: /etc/cron.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97346,7 +111204,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/cron.allow - file: + ansible.builtin.file: path: /etc/cron.allow mode: u-xs,g-xws,o-xwrt when: @@ -97473,17 +111331,18 @@ data transmission between client and server. Any confidential data can be listened and no integrity checking is made. # CAUTION: This remediation script will remove inetutils-telnetd -# from the system, and may remove any packages -# that depend on inetutils-telnetd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on inetutils-telnetd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "inetutils-telnetd" ; then yum remove -y "inetutils-telnetd" fi - - name: Ensure inetutils-telnetd is removed - package: + - name: 'Uninstall the inet-based telnet server: Ensure inetutils-telnetd is removed' + ansible.builtin.package: name: inetutils-telnetd state: absent tags: @@ -97497,7 +111356,8 @@ fi - no_reboot_needed - package_inetutils-telnetd_removed - include remove_inetutils-telnetd + +include remove_inetutils-telnetd class remove_inetutils-telnetd { package { 'inetutils-telnetd': @@ -97506,6 +111366,7 @@ class remove_inetutils-telnetd { } + package --remove=inetutils-telnetd @@ -97519,17 +111380,18 @@ package --remove=inetutils-telnetd NIS does not support efficiently security constraints, ACL, etc. and should not be used. # CAUTION: This remediation script will remove nis -# from the system, and may remove any packages -# that depend on nis. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on nis. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "nis" ; then yum remove -y "nis" fi - - name: Ensure nis is removed - package: + - name: 'Uninstall the nis package: Ensure nis is removed' + ansible.builtin.package: name: nis state: absent tags: @@ -97540,7 +111402,8 @@ fi - no_reboot_needed - package_nis_removed - include remove_nis + +include remove_nis class remove_nis { package { 'nis': @@ -97549,6 +111412,7 @@ class remove_nis { } + package --remove=nis @@ -97652,17 +111516,18 @@ package --remove=nis When remote shell is required, up-to-date ssh daemon can be used. # CAUTION: This remediation script will remove telnetd-ssl -# from the system, and may remove any packages -# that depend on telnetd-ssl. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnetd-ssl. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnetd-ssl" ; then yum remove -y "telnetd-ssl" fi - - name: Ensure telnetd-ssl is removed - package: + - name: 'Uninstall the ssl compliant telnet server: Ensure telnetd-ssl is removed' + ansible.builtin.package: name: telnetd-ssl state: absent tags: @@ -97676,7 +111541,8 @@ fi - no_reboot_needed - package_telnetd-ssl_removed - include remove_telnetd-ssl + +include remove_telnetd-ssl class remove_telnetd-ssl { package { 'telnetd-ssl': @@ -97685,6 +111551,7 @@ class remove_telnetd-ssl { } + package --remove=telnetd-ssl @@ -97789,17 +111656,18 @@ any data transmission between client and server. Any confidential data can be listened and no integrity checking is made.' # CAUTION: This remediation script will remove telnetd -# from the system, and may remove any packages -# that depend on telnetd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnetd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnetd" ; then yum remove -y "telnetd" fi - - name: Ensure telnetd is removed - package: + - name: 'Uninstall the telnet server: Ensure telnetd is removed' + ansible.builtin.package: name: telnetd state: absent tags: @@ -97813,7 +111681,8 @@ fi - no_reboot_needed - package_telnetd_removed - include remove_telnetd + +include remove_telnetd class remove_telnetd { package { 'telnetd': @@ -97822,6 +111691,7 @@ class remove_telnetd { } + package --remove=telnetd @@ -98021,7 +111891,6 @@ $ sudo yum erase dhcp-server DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -98085,17 +111954,18 @@ $ sudo yum erase dhcp-server accidentally reactivated and disrupt network operation. # CAUTION: This remediation script will remove dhcp -# from the system, and may remove any packages -# that depend on dhcp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on dhcp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "dhcp" ; then yum remove -y "dhcp" fi - - name: Ensure dhcp is removed - package: + - name: 'Uninstall DHCP Server Package: Ensure dhcp is removed' + ansible.builtin.package: name: dhcp state: absent tags: @@ -98111,7 +111981,8 @@ fi - no_reboot_needed - package_dhcp_removed - include remove_dhcp + +include remove_dhcp class remove_dhcp { package { 'dhcp': @@ -98120,6 +111991,7 @@ class remove_dhcp { } + package --remove=dhcp @@ -98163,7 +112035,6 @@ $ sudo yum erase bind DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -98225,17 +112096,18 @@ $ sudo yum erase bind removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove bind -# from the system, and may remove any packages -# that depend on bind. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on bind. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "bind" ; then yum remove -y "bind" fi - - name: Ensure bind is removed - package: + - name: 'Uninstall bind Package: Ensure bind is removed' + ansible.builtin.package: name: bind state: absent tags: @@ -98249,7 +112121,8 @@ fi - no_reboot_needed - package_bind_removed - include remove_bind + +include remove_bind class remove_bind { package { 'bind': @@ -98258,6 +112131,7 @@ class remove_bind { } + package --remove=bind @@ -98282,16 +112156,15 @@ makes use of the kernel's fanotify interface to determine $ sudo yum install fapolicyd - CCI-001774 - CCI-001764 CM-6(a) SI-4(22) FMT_SMF_EXT.1 - SRG-OS-000370-GPOS-00155 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00230 - OL09-00-000340 - SV-271506r1091230_rule + SRG-OS-000370-GPOS-00155 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00230 + 1409 + OL09-00-000340 + SV-271506r1091230_rule fapolicyd (File Access Policy Daemon) implements application whitelisting to decide file access rights. # Remediation is applicable only in certain platforms @@ -98320,7 +112193,7 @@ fi - package_fapolicyd_installed - name: Ensure fapolicyd is installed - package: + ansible.builtin.package: name: fapolicyd state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -98365,16 +112238,15 @@ version = "*" The fapolicyd service can be enabled with the following command: $ sudo systemctl enable fapolicyd.service - CCI-001774 - CCI-001764 CM-6(a) SI-4(22) FMT_SMF_EXT.1 - SRG-OS-000370-GPOS-00155 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00230 - OL09-00-000341 - SV-271507r1091233_rule + SRG-OS-000370-GPOS-00155 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00230 + 1409 + OL09-00-000341 + SV-271507r1091233_rule The fapolicyd service (File Access Policy Daemon) implements application whitelisting to decide file access rights. # Remediation is applicable only in certain platforms @@ -98409,7 +112281,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the File Access Policy Service - Enable Service fapolicyd @@ -98420,7 +112292,6 @@ fi masked: false when: - '"fapolicyd" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000341 - NIST-800-53-CM-6(a) @@ -98431,6 +112302,8 @@ fi - medium_severity - no_reboot_needed - service_fapolicyd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_fapolicyd @@ -98445,6 +112318,10 @@ class enable_fapolicyd { [customizations.services] enabled = ["fapolicyd"] + + + + @@ -98455,13 +112332,12 @@ enabled = ["fapolicyd"] Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. The Fapolicy module must be configured to employ a deny-all, permit-by-exception policy to allow the execution of authorized software programs and to prevent unauthorized software from running. - CCI-001764 CM-7 (2) CM-7 (5) (b) CM-6 b - SRG-OS-000368-GPOS-00154 - SRG-OS-000370-GPOS-00155 - SRG-OS-000480-GPOS-00232 + SRG-OS-000368-GPOS-00154 + SRG-OS-000370-GPOS-00155 + SRG-OS-000480-GPOS-00232 Utilizing a whitelist provides a configuration management method for allowing the execution of only authorized software. Using only authorized software decreases risk by limiting the number of potential vulnerabilities. Verification of whitelisted software occurs prior to execution or at system startup. @@ -98513,6 +112389,22 @@ fi - no_reboot_needed - restrict_strategy +- name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy + to Allow the Execution of Authorized Software Programs. - Gather the package facts + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6 b + - NIST-800-53-CM-7 (2) + - NIST-800-53-CM-7 (5) (b) + - fapolicy_default_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. - Ensure a Final Rule Denying Everything @@ -98523,8 +112415,10 @@ fi owner: root group: fapolicyd mode: '0644' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"fapolicyd" in ansible_facts.packages' register: result_fapolicyd_final_rule - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6 b - NIST-800-53-CM-7 (2) @@ -98544,8 +112438,10 @@ fi regexp: ^(permissive\s*=).*$ line: \1 0 backrefs: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"fapolicyd" in ansible_facts.packages' register: result_fapolicyd_enforced - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6 b - NIST-800-53-CM-7 (2) @@ -98565,6 +112461,7 @@ fi state: restarted when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"fapolicyd" in ansible_facts.packages' - result_fapolicyd_final_rule is changed or result_fapolicyd_enforced is changed tags: - NIST-800-53-CM-6 b @@ -98589,9 +112486,8 @@ fi fapolicyd needs be configured so that users cannot give access to their home folders to other users. This rule is deprecated and there is no replacement at this time. Previous versions of this rule provided fixtext that would cause fapolicyd not to start. - CCI-000366 CM-6 b - SRG-OS-000480-GPOS-00230 + SRG-OS-000480-GPOS-00230 Users' home directories/folders may contain information of a sensitive nature. Non-privileged users should coordinate any sharing of information with a System Administrator (SA) through shared resources. fapolicyd can confine users to their home directory, not allowing them to make any changes outside of their own home directories. @@ -98629,17 +112525,18 @@ to run the system as a FTP server (for example, to allow anonymous downloads), i recommended that the package be removed to reduce the potential attack surface. # CAUTION: This remediation script will remove ftp -# from the system, and may remove any packages -# that depend on ftp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on ftp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "ftp" ; then yum remove -y "ftp" fi - - name: Ensure ftp is removed - package: + - name: 'Remove ftp Package: Ensure ftp is removed' + ansible.builtin.package: name: ftp state: absent tags: @@ -98652,7 +112549,8 @@ fi - no_reboot_needed - package_ftp_removed - include remove_ftp + +include remove_ftp class remove_ftp { package { 'ftp': @@ -98661,6 +112559,7 @@ class remove_ftp { } + package --remove=ftp @@ -98689,9 +112588,6 @@ possible. DSS05.02 DSS05.05 DSS06.06 - CCI-000366 - CCI-000197 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -98752,27 +112648,28 @@ possible. CM-7.1(ii) PR.IP-1 PR.PT-3 - SRG-OS-000074-GPOS-00042 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 + SRG-OS-000074-GPOS-00042 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL4 - OL09-00-000130 - SV-271462r1091098_rule + OL09-00-000130 + SV-271462r1091098_rule Removing the vsftpd package decreases the risk of its accidental activation. # CAUTION: This remediation script will remove vsftpd -# from the system, and may remove any packages -# that depend on vsftpd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on vsftpd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "vsftpd" ; then yum remove -y "vsftpd" fi - - name: Ensure vsftpd is removed - package: + - name: 'Uninstall vsftpd Package: Ensure vsftpd is removed' + ansible.builtin.package: name: vsftpd state: absent tags: @@ -98791,7 +112688,8 @@ fi - no_reboot_needed - package_vsftpd_removed - include remove_vsftpd + +include remove_vsftpd class remove_vsftpd { package { 'vsftpd': @@ -98800,6 +112698,7 @@ class remove_vsftpd { } + package --remove=vsftpd @@ -98875,17 +112774,18 @@ $ sudo yum erase cyrus-imapd removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove cyrus-imapd -# from the system, and may remove any packages -# that depend on cyrus-imapd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on cyrus-imapd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "cyrus-imapd" ; then yum remove -y "cyrus-imapd" fi - - name: Ensure cyrus-imapd is removed - package: + - name: 'Uninstall cyrus-imapd Package: Ensure cyrus-imapd is removed' + ansible.builtin.package: name: cyrus-imapd state: absent tags: @@ -98896,7 +112796,8 @@ fi - package_cyrus-imapd_removed - unknown_severity - include remove_cyrus-imapd + +include remove_cyrus-imapd class remove_cyrus-imapd { package { 'cyrus-imapd': @@ -98905,6 +112806,7 @@ class remove_cyrus-imapd { } + package --remove=cyrus-imapd @@ -98931,17 +112833,18 @@ $ sudo yum erase dovecot removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove dovecot -# from the system, and may remove any packages -# that depend on dovecot. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on dovecot. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "dovecot" ; then yum remove -y "dovecot" fi - - name: Ensure dovecot is removed - package: + - name: 'Uninstall dovecot Package: Ensure dovecot is removed' + ansible.builtin.package: name: dovecot state: absent tags: @@ -98952,7 +112855,8 @@ fi - package_dovecot_removed - unknown_severity - include remove_dovecot + +include remove_dovecot class remove_dovecot { package { 'dovecot': @@ -98961,6 +112865,7 @@ class remove_dovecot { } + package --remove=dovecot @@ -99005,8 +112910,7 @@ The postfix package can be installed with the following c $ sudo yum install postfix - CCI-000139 - SRG-OS-000046-GPOS-00022 + SRG-OS-000046-GPOS-00022 Emails can be used to notify designated personnel about important system events such as failures or warnings. # Remediation is applicable only in certain platforms @@ -99032,7 +112936,7 @@ fi - package_postfix_installed - name: Ensure postfix is installed - package: + ansible.builtin.package: name: postfix state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -99074,11 +112978,10 @@ The s-nail package can be installed with the following co $ sudo yum install s-nail - CCI-001744 CM-3(5) - SRG-OS-000363-GPOS-00150 - OL09-00-000290 - SV-271495r1091197_rule + SRG-OS-000363-GPOS-00150 + OL09-00-000290 + SV-271495r1091197_rule Emails can be used to notify designated personnel about important system events such as failures or warnings. # Remediation is applicable only in certain platforms @@ -99106,7 +113009,7 @@ fi - package_s-nail_installed - name: Ensure s-nail is installed - package: + ansible.builtin.package: name: s-nail state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -99162,8 +113065,6 @@ $ sudo yum erase sendmail DSS05.02 DSS05.05 DSS06.06 - CCI-000366 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -99220,11 +113121,11 @@ $ sudo yum erase sendmail CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 - SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + SRG-OS-000095-GPOS-00049 R62 - OL09-00-000150 - SV-271466r1091110_rule + OL09-00-000150 + SV-271466r1091110_rule The sendmail software was not developed with security in mind and its design prevents it from being effectively contained by SELinux. Postfix should be used instead. @@ -99232,10 +113133,11 @@ should be used instead. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove sendmail -# from the system, and may remove any packages -# that depend on sendmail. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on sendmail. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "sendmail" ; then yum remove -y "sendmail" @@ -99260,8 +113162,8 @@ fi - no_reboot_needed - package_sendmail_removed -- name: Ensure sendmail is removed - package: +- name: 'Uninstall Sendmail Package: Ensure sendmail is removed' + ansible.builtin.package: name: sendmail state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -99277,7 +113179,8 @@ fi - no_reboot_needed - package_sendmail_removed - include remove_sendmail + +include remove_sendmail class remove_sendmail { package { 'sendmail': @@ -99286,6 +113189,7 @@ class remove_sendmail { } + package --remove=sendmail @@ -99336,7 +113240,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable Postfix Service - Enable Service postfix @@ -99347,14 +113251,15 @@ fi masked: false when: - '"postfix" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity - low_disruption - no_reboot_needed - service_postfix_enabled + - special_service_block - unknown_severity + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_postfix @@ -99369,6 +113274,10 @@ class enable_postfix { [customizations.services] enabled = ["postfix"] + + + + @@ -99408,12 +113317,11 @@ configure the alias: $ sudo echo "root: " >> /etc/aliases $ sudo newaliases - CCI-000139 CM-6(a) - SRG-OS-000046-GPOS-00022 + SRG-OS-000046-GPOS-00022 R75 - OL09-00-002405 - SV-271744r1091944_rule + OL09-00-002405 + SV-271744r1091944_rule A number of system services utilize email messages sent to the root user to notify system administrators of active or impending issues. These messages must be forwarded to at least one monitored email address. @@ -99433,12 +113341,11 @@ Check that the "/etc/aliases" file has a defined value for "root". postmaster: root - CCI-000139 AU-5(a) AU-5.1(ii) - SRG-OS-000046-GPOS-00022 - OL09-00-000815 - SV-271589r1091479_rule + SRG-OS-000046-GPOS-00022 + OL09-00-000815 + SV-271589r1091479_rule It is critical for the appropriate personnel to be aware if a system is at risk of failing to process audit logs as required. Without this notification, the security personnel may be unaware of an impending failure of the audit capability, and system operation may be adversely @@ -99490,7 +113397,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/aliases create: true regexp: (?i)^\s*postmaster\s*:\s* @@ -99500,7 +113407,7 @@ fi register: dupes - name: Deduplicate values from /etc/aliases - lineinfile: + ansible.builtin.lineinfile: path: /etc/aliases create: true regexp: (?i)^\s*postmaster\s*:\s* @@ -99508,12 +113415,13 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/aliases - lineinfile: + ansible.builtin.lineinfile: path: /etc/aliases create: true regexp: (?i)^\s*postmaster\s*:\s* line: 'postmaster: root' state: present + register: aliases_postmaster_changed when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000815 @@ -99526,7 +113434,8 @@ fi - no_reboot_needed - postfix_client_configure_mail_alias_postmaster -- name: Check if newaliases command is available +- name: Configure System to Forward All Mail From Postmaster to The Root Account - + Check if newaliases command is available ansible.builtin.stat: path: /usr/bin/newaliases register: result_newaliases_present @@ -99542,12 +113451,14 @@ fi - no_reboot_needed - postfix_client_configure_mail_alias_postmaster -- name: Update postfix aliases +- name: Configure System to Forward All Mail From Postmaster to The Root Account - + Update postfix aliases ansible.builtin.command: cmd: newaliases when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_newaliases_present.stat.exists + - aliases_postmaster_changed is changed tags: - DISA-STIG-OL09-00-000815 - NIST-800-53-AU-5(a) @@ -99600,7 +113511,6 @@ may help prevent spam or viruses from being delivered. DSS05.02 DSS05.05 DSS06.06 - CCI-000382 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -99691,13 +113601,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: XCCDF Value var_postfix_inet_interfaces # promote to variable - set_fact: - var_postfix_inet_interfaces: !!str - tags: - - always - -- name: Gather list of packages + - name: Gather the package facts package_facts: manager: auto tags: @@ -99712,9 +113616,33 @@ fi - no_reboot_needed - postfix_network_listening_disabled - restrict_strategy +- name: XCCDF Value var_postfix_inet_interfaces # promote to variable + set_fact: + var_postfix_inet_interfaces: !!str + tags: + - always + +- name: Gather list of packages + ansible.builtin.package_facts: + manager: auto + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"postfix" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_network_listening_disabled + - restrict_strategy - name: Make changes to Postfix configuration file - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: false regexp: (?i)^inet_interfaces\s*=\s.* @@ -99772,10 +113700,9 @@ trusted to relay unconditionally, configure SMTP AUTH with SSL support.$ sudo postconf -e 'smtpd_client_restrictions = permit_mynetworks,reject' - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002425 - SV-271763r1092001_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002425 + SV-271763r1092001_rule If unrestricted mail relaying is permitted, unauthorized senders could use this host as a mail relay for the purpose of sending spam or other unauthorized activity. @@ -99809,7 +113736,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: true regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* @@ -99819,7 +113746,7 @@ fi register: dupes - name: Deduplicate values from /etc/postfix/main.cf - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: true regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* @@ -99827,7 +113754,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/postfix/main.cf - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: true regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* @@ -99870,10 +113797,9 @@ clients, as well as to those operating as NFS servers. $ sudo yum erase nfs-utils - CCI-000381 - SRG-OS-000095-GPOS-00049 - OL09-00-000100 - SV-271456r1091080_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000100 + SV-271456r1091080_rule nfs-utils provides a daemon for the kernel NFS server and related tools. This package also contains the showmount program. showmount queries the mount daemon on a remote host for information about the Network File System (NFS) server on the @@ -99881,17 +113807,18 @@ remote host. For example, showmount can display the clien that host. # CAUTION: This remediation script will remove nfs-utils -# from the system, and may remove any packages -# that depend on nfs-utils. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on nfs-utils. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "nfs-utils" ; then yum remove -y "nfs-utils" fi - - name: Ensure nfs-utils is removed - package: + - name: 'Uninstall nfs-utils Package: Ensure nfs-utils is removed' + ansible.builtin.package: name: nfs-utils state: absent tags: @@ -99903,7 +113830,8 @@ fi - no_reboot_needed - package_nfs-utils_removed - include remove_nfs-utils + +include remove_nfs-utils class remove_nfs-utils { package { 'nfs-utils': @@ -99912,6 +113840,7 @@ class remove_nfs-utils { } + package --remove=nfs-utils @@ -99955,7 +113884,6 @@ any NFS mounts. DSS05.04 DSS05.10 DSS06.10 - CCI-000366 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -99995,9 +113923,9 @@ any NFS mounts. AC-17(a) PR.AC-4 PR.AC-7 - SRG-OS-000480-GPOS-00227 - OL09-00-002010 - SV-271640r1091632_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002010 + SV-271640r1091632_rule When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle requests from the remote user. The userid and groupid could mistakenly or maliciously be set incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client @@ -100057,7 +113985,8 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have sec=krb5:krb5i:krb5p - command: findmnt --fstab --types nfs,nfs4 -O nosec=krb5:krb5i:krb5p -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nosec=krb5:krb5i:krb5p + -n -P register: points_register check_mode: false changed_when: false @@ -100080,7 +114009,7 @@ fi - no_reboot_needed - name: Add sec=krb5:krb5i:krb5p to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100132,7 +114061,6 @@ any NFS mounts. DSS05.05 DSS05.06 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -100195,9 +114123,9 @@ any NFS mounts. PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002011 - SV-271641r1091635_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002011 + SV-271641r1091635_rule Legitimate device files should only exist in the /dev directory. NFS mounts should not present device files to users. @@ -100250,7 +114178,7 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have nodev - command: findmnt --fstab --types nfs,nfs4 -O nonodev -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nonodev -n -P register: points_register check_mode: false changed_when: false @@ -100268,7 +114196,7 @@ fi - no_reboot_needed - name: Add nodev to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100312,7 +114240,6 @@ any NFS mounts. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -100345,9 +114272,9 @@ any NFS mounts. CM-6(a) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002012 - SV-271642r1092593_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002012 + SV-271642r1092593_rule The noexec mount option causes the system not to execute binary files. This option must be used for mounting any file system not containing approved binary files as they may be incompatible. Executing files from untrusted file systems increases the opportunity for unprivileged users to attain unauthorized @@ -100404,7 +114331,7 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have noexec - command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n -P register: points_register check_mode: false changed_when: false @@ -100424,7 +114351,7 @@ fi - no_reboot_needed - name: Add noexec to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100470,7 +114397,6 @@ any NFS mounts. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -100502,9 +114428,9 @@ any NFS mounts. CM6(a) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002013 - SV-271643r1091641_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002013 + SV-271643r1091641_rule NFS mounts should not present suid binaries to users. Only vendor-supplied suid executables should be installed to their default location on the local filesystem. @@ -100558,7 +114484,7 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have nosuid - command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n -P register: points_register check_mode: false changed_when: false @@ -100577,7 +114503,7 @@ fi - no_reboot_needed - name: Add nosuid to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100639,7 +114565,6 @@ add sec=krb5:krb5i:krb5p to each export in /et DSS05.04 DSS05.10 DSS06.10 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -100685,12 +114610,15 @@ add sec=krb5:krb5i:krb5p to each export in /et AC-17(a) PR.AC-4 PR.AC-7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle requests from the remote user. The userid and groupid could mistakenly or maliciously be set incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client systems to more securely authenticate the remote mount request. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + nfs_exports=() readarray -t nfs_exports < <(grep -E "^/.*[[:space:]]+ .*\(.*\)[[:space:]]*$" /etc/exports | awk '{print $2}') @@ -100704,12 +114632,35 @@ do fi sed -i "s|$nfs_export|$correct_export|g" /etc/exports done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Drop any security clause for every export - replace: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - use_kerberos_security_all_exports + +- name: Drop any security clause for every export + ansible.builtin.replace: path: /etc/exports regexp: ^(/.*\w+.*\(.*),sec=[^,]*(.*\)\w*$) replace: \1\2 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(a) @@ -100726,10 +114677,11 @@ done - use_kerberos_security_all_exports - name: Add kerberos security when no security is defined for an export - replace: + ansible.builtin.replace: path: /etc/exports regexp: ^(/.*\w+.*\(.*)(\)\w*$) replace: \1,sec=krb5:krb5i:krb5p\2 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(a) @@ -100790,7 +114742,7 @@ packages respectively. The default chronyd daemon can work well when external time references -are only intermittently accesible, can perform well even when the network is +are only intermittently accessible, can perform well even when the network is congested for longer periods of time, can usually synchronize the clock faster and with better time accuracy, and quickly adapts to sudden changes in the rate of the clock, for example, due to changes in the temperature of the crystal @@ -100835,6 +114787,8 @@ information on the capabilities and configuration of each of the NTP daemons.0.ntp.cloud.aliyuncs.com,1.ntp.aliyun.com,2.ntp1.aliyun.com,3.ntp1.cloud.aliyuncs.com 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org 0.ubuntu.pool.ntp.org,1.ubuntu.pool.ntp.org,2.ubuntu.pool.ntp.org,3.ubuntu.pool.ntp.org + 0.debian.pool.ntp.org,1.debian.pool.ntp.org,2.debian.pool.ntp.org,3.debian.pool.ntp.org + time.nist.gov Vendor Approved Time Servers @@ -100850,6 +114804,8 @@ information on the capabilities and configuration of each of the NTP daemons.0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org 0.ubuntu.pool.ntp.org,1.ubuntu.pool.ntp.org,2.ubuntu.pool.ntp.org,3.ubuntu.pool.ntp.org 0.almalinux.pool.ntp.org,1.almalinux.pool.ntp.org,2.almalinux.pool.ntp.org,3.almalinux.pool.ntp.org + 0.debian.pool.ntp.org,1.debian.pool.ntp.org,2.debian.pool.ntp.org,3.debian.pool.ntp.org + time.nist.gov,time-a-g.nist.gov,time-b-g.nist.gov,time-c-g.nist.gov Maximum NTP or Chrony Poll @@ -100868,18 +114824,17 @@ The chrony package can be installed with the following co $ sudo yum install chrony - CCI-004923 - 0988 - 1405 FMT_SMF_EXT.1 Req-10.4 - SRG-OS-000355-GPOS-00143 + SRG-OS-000355-GPOS-00143 R71 A.3.SEC-OL3 + 0988 + 1405 10.6.1 10.6 - OL09-00-000310 - SV-271501r1091215_rule + OL09-00-000310 + SV-271501r1091215_rule Time synchronization is important to support time sensitive security mechanisms like Kerberos and also ensures log files have consistent time records across the enterprise, which aids in forensic investigations. @@ -100910,7 +114865,7 @@ fi - package_chrony_installed - name: Ensure chrony is installed - package: + ansible.builtin.package: name: chrony state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -100960,12 +114915,12 @@ Chrony can be configured to be a client and/or a server. To enable Chronyd service, you can run: # systemctl enable chronyd.service This recommendation only applies if chrony is in use on the system. - CCI-004923 + SRG-OS-000355-GPOS-00143 + R71 0988 1405 - SRG-OS-000355-GPOS-00143 - OL09-00-000311 - SV-271502r1091218_rule + OL09-00-000311 + SV-271502r1091218_rule If chrony is in use on the system proper configuration is vital to ensuring time synchronization is working properly. @@ -100999,7 +114954,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: The Chronyd service is enabled - Enable Service chronyd @@ -101010,9 +114965,6 @@ fi masked: false when: - '"chrony" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - '"chrony" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000311 - enable_strategy @@ -101021,6 +114973,10 @@ fi - medium_severity - no_reboot_needed - service_chronyd_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' include enable_chronyd @@ -101035,6 +114991,10 @@ class enable_chronyd { [customizations.services] enabled = ["chronyd"] + + + + @@ -101053,17 +115013,14 @@ accurate. More information on chrony can be found at Add or edit server or pool lines to /etc/chrony.conf as appropriate: server <remote-server> Multiple servers may be configured. - CCI-001890 - CCI-004926 - CCI-004923 - 0988 - 1405 CM-6(a) AU-8(1)(a) Req-10.4.3 - SRG-OS-000355-GPOS-00143 + SRG-OS-000355-GPOS-00143 R71 A.3.SEC-OL3 + 0988 + 1405 10.6.2 10.6 If chrony is in use on the system proper configuration is vital to ensuring time @@ -101085,6 +115042,9 @@ if ! grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$config_ else sed -i 's/#[ \t]*server/server/g' "$config_file" fi + if [[ -s "$config_file" ]] && [[ -n "$(tail -c 1 -- "$config_file" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "$config_file" + fi fi else @@ -101113,7 +115073,7 @@ fi - always - name: Detect if chrony is already configured with pools or servers - find: + ansible.builtin.find: path: /etc patterns: chrony.conf contains: ^[\s]*(?:server|pool)[\s]+[\w]+ @@ -101135,7 +115095,7 @@ fi - no_reboot_needed - name: Configure remote time servers - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf line: server {{ item }} state: present @@ -101170,15 +115130,13 @@ fi The port option in /etc/chrony.conf can be set to 0 to make chrony daemon to never open any listening port for server operation and to operate strictly in a client-only mode. - CCI-000382 - CCI-000381 AU-8(1) AU-12(1) FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000095-GPOS-00049 - OL09-00-002320 - SV-271697r1091803_rule + SRG-OS-000096-GPOS-00050 + SRG-OS-000095-GPOS-00049 + OL09-00-002320 + SV-271697r1091803_rule In order to prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information systems. Operating systems are capable of providing a wide variety of functions and services. Some of the functions and services provided by default may not be necessary to support essential organizational operations. Additionally, it is sometimes convenient to provide multiple services from a single component (e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by any one component. To support the requirements and principles of least functionality, the operating system must support the organizational requirements, providing only essential capabilities and limiting the use of ports, protocols, and/or services to only those required, authorized, and approved to conduct official business or to address authorized quality of life issues. @@ -101228,7 +115186,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*port\s+ @@ -101238,7 +115196,7 @@ fi register: dupes - name: Deduplicate values from /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*port\s+ @@ -101246,7 +115204,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*port\s+ @@ -101284,14 +115242,12 @@ accurate. More information on chrony can be found at Add or edit server or pool lines to /etc/chrony.conf as appropriate: server <remote-server> Multiple servers may be configured. - CCI-000160 - CCI-001891 - 0988 - 1405 CM-6(a) AU-8(1)(a) Req-10.4.3 R71 + 0988 + 1405 If chrony is in use on the system proper configuration is vital to ensuring time synchronization is working properly. @@ -101419,13 +115375,11 @@ fi The cmdport option in /etc/chrony.conf can be set to 0 to stop chrony daemon from listening on the UDP port 323 for management connections made by chronyc. - CCI-000382 - CCI-000381 CM-7(1) - SRG-OS-000096-GPOS-00050 - SRG-OS-000095-GPOS-00049 - OL09-00-002321 - SV-271698r1091806_rule + SRG-OS-000096-GPOS-00050 + SRG-OS-000095-GPOS-00049 + OL09-00-002321 + SV-271698r1091806_rule Minimizing the exposure of the server functionality of the chrony daemon diminishes the attack surface. @@ -101473,7 +115427,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*cmdport\s+ @@ -101483,7 +115437,7 @@ fi register: dupes - name: Deduplicate values from /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*cmdport\s+ @@ -101491,7 +115445,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*cmdport\s+ @@ -101540,9 +115494,6 @@ should be configured too. DSS05.04 DSS05.07 MEA02.01 - CCI-001890 - CCI-004926 - CCI-004923 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -101563,11 +115514,11 @@ should be configured too. AU-8(1)(b) AU-12(1) PR.PT-1 - SRG-OS-000355-GPOS-00143 - SRG-OS-000356-GPOS-00144 - SRG-OS-000359-GPOS-00146 - OL09-00-002323 - SV-271699r1091809_rule + SRG-OS-000355-GPOS-00143 + SRG-OS-000356-GPOS-00144 + SRG-OS-000359-GPOS-00146 + OL09-00-002323 + SV-271699r1091809_rule Inaccurate time stamps make it more difficult to correlate events and can lead to an inaccurate analysis. Determining the correct time a particular event occurred on a system is critical when conducting forensic analysis and investigating system events. Sources outside the configured acceptable allowance (drift) may be inaccurate. Synchronizing internal information system clocks provides uniformity of time stamps for information systems with multiple system clocks and systems connected over a network. Organizations should consider endpoints that may not have regular access to the authoritative time server (e.g., mobile, teleworking, and tactical endpoints). @@ -101586,7 +115537,9 @@ pof="/usr/sbin/pidof" CONFIG_FILES="/etc/ntp.conf" $pof ntpd || { CHRONY_D_PATH=/etc/chrony.d/ + mapfile -t CONFIG_FILES < <(find ${CHRONY_D_PATH}.* -type f -name '*.conf') + CONFIG_FILES+=(/etc/chrony.conf) } @@ -101830,9 +115783,6 @@ production environment, the Oracle Linux 9 system can be configured to utilize the services of the chronyd NTP daemon (the default), or services of the ntpd NTP daemon. Refer to - - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-configuring_ntp_using_the_chrony_suite - for more detailed comparison of the features of both of the choices, and for further guidance how to choose between the two NTP daemons. @@ -101869,8 +115819,6 @@ hostname of a remote NTP server for ntpserver: SR 2.12 SR 2.8 SR 2.9 - 0988 - 1405 A.12.4.1 A.12.4.2 A.12.4.3 @@ -101882,6 +115830,8 @@ hostname of a remote NTP server for ntpserver: AU-12(1) PR.PT-1 Req-10.4.3 + 0988 + 1405 Specifying additional NTP servers increases the availability of accurate time data, in the event that one of the specified servers becomes unavailable. This is typical for a system acting as an NTP server for @@ -101904,6 +115854,9 @@ if ! [ "$(grep -c '^server' "$config_file")" -gt 1 ] ; then else sed -i 's/#[ \t]*server/server/g' "$config_file" fi + if [[ -s "$config_file" ]] && [[ -n "$(tail -c 1 -- "$config_file" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "$config_file" + fi fi else @@ -101932,7 +115885,7 @@ fi - always - name: Detect if chrony configuration file is present - find: + ansible.builtin.find: path: /etc patterns: chrony.conf register: chrony_server_config @@ -101953,7 +115906,7 @@ fi - no_reboot_needed - name: Configure multiple time servers in chrony config - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf line: server {{ item }} state: present @@ -101977,7 +115930,7 @@ fi - no_reboot_needed - name: Detect if NTP configuration file is present - find: + ansible.builtin.find: path: /etc patterns: ntp.conf register: ntp_server_config @@ -101998,7 +115951,7 @@ fi - no_reboot_needed - name: Configure multiple time servers in NTP config - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf line: pool {{ item }} state: present @@ -102078,7 +116031,7 @@ fi - no_reboot_needed - name: Detect if file /etc/sysconfig/chronyd is not empty or missing - find: + ansible.builtin.find: path: /etc/sysconfig/ patterns: chronyd contains: ^([\s]*OPTIONS=["]?[^"]*)("?) @@ -102097,7 +116050,7 @@ fi - no_reboot_needed - name: Remove any previous configuration of user used to run chronyd process - replace: + ansible.builtin.replace: path: /etc/sysconfig/chronyd regexp: \s*-u\s*\w+\s* replace: ' ' @@ -102126,14 +116079,11 @@ fi Ensure Chrony is only configured with the server directive Check that Chrony only has time sources configured with the server directive. This rule doesn't come with a remediation, the time source needs to be added by the administrator. - CCI-001890 - CCI-004926 - CCI-004923 - SRG-OS-000355-GPOS-00143 - SRG-OS-000356-GPOS-00144 - SRG-OS-000359-GPOS-00146 - OL09-00-002323 - SV-271699r1091809_rule + SRG-OS-000355-GPOS-00143 + SRG-OS-000356-GPOS-00144 + SRG-OS-000359-GPOS-00146 + OL09-00-002323 + SV-271699r1091809_rule Depending on the infrastructure being used the pool directive may not be supported. Using the server directive allows for better control of where the system gets time data from. @@ -102146,7 +116096,8 @@ Using the server directive allows for better control of w Verify Group Who Owns /etc/chrony.keys File - To properly set the group owner of /etc/chrony.keys, run the command: $ sudo chgrp chrony /etc/chrony.keys + To properly set the group owner of /etc/chrony.keys, run the command: +$ sudo chgrp chrony /etc/chrony.keys R50 The ownership of the /etc/chrony.keys file by the chrony group is important @@ -102156,7 +116107,19 @@ chrony ensures exclusive control of the chrony cryptography keys.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp chrony /etc/chrony.keys +newgroup="" +if getent group "chrony" >/dev/null 2>&1; then + newgroup="chrony" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "chrony is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/chrony.keys" | grep -E -w -q "chrony"; then + chgrp --no-dereference "$newgroup" /etc/chrony.keys +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -102173,8 +116136,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the chrony group is defined + ansible.builtin.getent: + database: group + key: chrony + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_chrony_keys_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_chrony_keys_newgroup variable if chrony found + ansible.builtin.set_fact: + file_groupowner_etc_chrony_keys_newgroup: chrony + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["chrony"] is defined + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/chrony.keys - stat: + ansible.builtin.stat: path: /etc/chrony.keys register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -102186,10 +116179,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner chrony on /etc/chrony.keys - file: +- name: Ensure group owner on /etc/chrony.keys + ansible.builtin.file: path: /etc/chrony.keys - group: chrony + follow: false + group: '{{ file_groupowner_etc_chrony_keys_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -102210,7 +116204,8 @@ fi Verify User Who Owns /etc/chrony.keys File - To properly set the owner of /etc/chrony.keys, run the command: $ sudo chown root /etc/chrony.keys + To properly set the owner of /etc/chrony.keys, run the command: +$ sudo chown root /etc/chrony.keys R50 The ownership of the /etc/chrony.keys file by the chrony user is important @@ -102220,7 +116215,19 @@ chrony ensures exclusive control of the chrony cryptographic keys.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/chrony.keys +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/chrony.keys" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/chrony.keys +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -102237,8 +116244,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_chrony_keys_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_chrony_keys_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/chrony.keys - stat: + ansible.builtin.stat: path: /etc/chrony.keys register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -102250,10 +116269,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/chrony.keys - file: +- name: Ensure owner on /etc/chrony.keys + ansible.builtin.file: path: /etc/chrony.keys - owner: '0' + follow: false + owner: '{{ file_owner_etc_chrony_keys_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -102302,7 +116322,7 @@ fi - no_reboot_needed - name: Test for existence /etc/chrony.keys - stat: + ansible.builtin.stat: path: /etc/chrony.keys register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -102315,7 +116335,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/chrony.keys - file: + ansible.builtin.file: path: /etc/chrony.keys mode: u-xs,g-xws,o-xwrt when: @@ -102406,78 +116426,50 @@ fi - no_reboot_needed - service_rsyncd_disabled -- name: Ensure rsyncd service is disabled - Collect systemd Services Present in the - System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Ensure rsyncd service is disabled - Disable service rsyncd + block: + + - name: Ensure rsyncd service is disabled - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Ensure rsyncd service is disabled - Ensure rsyncd.service is Masked + ansible.builtin.systemd: + name: rsyncd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("rsyncd.service", multiline=True) + + - name: Unit Socket Exists - rsyncd.socket + ansible.builtin.command: systemctl -q list-unit-files rsyncd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Ensure rsyncd service is disabled - Disable Socket rsyncd + ansible.builtin.systemd: + name: rsyncd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("rsyncd.socket", multiline=True) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled - -- name: Ensure rsyncd service is disabled - Ensure rsyncd.service is Masked - ansible.builtin.systemd: - name: rsyncd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("rsyncd.service", multiline=True) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled - -- name: Unit Socket Exists - rsyncd.socket - ansible.builtin.command: systemctl -q list-unit-files rsyncd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled - -- name: Ensure rsyncd service is disabled - Disable Socket rsyncd - ansible.builtin.systemd: - name: rsyncd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("rsyncd.socket", multiline=True) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled include disable_rsyncd @@ -102492,6 +116484,10 @@ class disable_rsyncd { [customizations.services] masked = ["rsyncd"] + + + + @@ -102504,244 +116500,6 @@ masked = ["rsyncd"] The Berkeley r-commands are legacy services which allow cleartext remote access and have an insecure trust model. - - Uninstall rsh-server Package - The rsh-server package can be removed with the following command: - -$ sudo yum erase rsh-server - - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000381 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - IA-5(1)(c) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000095-GPOS-00049 - R62 - 2.2.4 - 2.2 - OL09-00-000105 - SV-271457r1091083_rule - The rsh-server service provides unencrypted remote access service which does not -provide for the confidentiality and integrity of user passwords or the remote session and has very weak -authentication. If a privileged user were to login using this service, the privileged user password -could be compromised. The rsh-server package provides several obsolete and insecure -network services. Removing it decreases the risk of those services' accidental (or intentional) -activation. - -# CAUTION: This remediation script will remove rsh-server -# from the system, and may remove any packages -# that depend on rsh-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "rsh-server" ; then -yum remove -y "rsh-server" -fi - - - name: Ensure rsh-server is removed - package: - name: rsh-server - state: absent - tags: - - DISA-STIG-OL09-00-000105 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_rsh-server_removed - - include remove_rsh-server - -class remove_rsh-server { - package { 'rsh-server': - ensure => 'purged', - } -} - - -package --remove=rsh-server - - - - - - - - - - Uninstall rsh Package - -The rsh package contains the client commands - -for the rsh services - 3.1.13 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - A.8.2.3 - A.13.1.1 - A.13.2.1 - A.13.2.3 - A.14.1.2 - A.14.1.3 - R62 - 2.2.4 - 2.2 - These legacy clients contain numerous security exposures and have -been replaced with the more secure SSH package. Even if the server is removed, -it is best to ensure the clients are also removed to prevent users from -inadvertently attempting to use these commands and therefore exposing - -their credentials. Note that removing the rsh package removes - -the clients for rsh,rcp, and rlogin. - -# CAUTION: This remediation script will remove rsh -# from the system, and may remove any packages -# that depend on rsh. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "rsh" ; then -yum remove -y "rsh" -fi - - - name: Ensure rsh is removed - package: - name: rsh - state: absent - tags: - - NIST-800-171-3.1.13 - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - package_rsh_removed - - unknown_severity - - include remove_rsh - -class remove_rsh { - package { 'rsh': - ensure => 'purged', - } -} - - -package --remove=rsh - - - - - - - - Disable rlogin Service The rlogin service, which is available with @@ -102779,7 +116537,6 @@ The rlogin socket can be disabled with the following comm DSS06.10 3.1.13 3.4.7 - CCI-001436 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -102921,93 +116678,53 @@ fi - no_reboot_needed - service_rlogin_disabled -- name: Disable rlogin Service - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable rlogin Service - Disable service rlogin + block: + + - name: Disable rlogin Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable rlogin Service - Ensure rlogin.service is Masked + ansible.builtin.systemd: + name: rlogin.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("rlogin.service", multiline=True) + + - name: Unit Socket Exists - rlogin.socket + ansible.builtin.command: systemctl -q list-unit-files rlogin.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable rlogin Service - Disable Socket rlogin + ansible.builtin.systemd: + name: rlogin.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("rlogin.socket", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Disable rlogin Service - Ensure rlogin.service is Masked - ansible.builtin.systemd: - name: rlogin.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("rlogin.service", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Unit Socket Exists - rlogin.socket - ansible.builtin.command: systemctl -q list-unit-files rlogin.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Disable rlogin Service - Disable Socket rlogin - ansible.builtin.systemd: - name: rlogin.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("rlogin.socket", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled include disable_rlogin @@ -103022,6 +116739,10 @@ class disable_rlogin { [customizations.services] masked = ["rlogin"] + + + + @@ -103035,10 +116756,9 @@ masked = ["rlogin"] system. To remove these files, run the following command to delete them from any location: $ sudo rm /[path]/[to]/[file]/shosts.equiv - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002419 - SV-271757r1092604_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002419 + SV-271757r1092604_rule The shosts.equiv files are used to configure host-based authentication for the system via SSH. Host-based authentication is not sufficient for preventing unauthorized access to the system, as it does not require interactive identification and authentication of a connection request, @@ -103058,6 +116778,7 @@ done ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -103247,7 +116968,6 @@ location: DSS05.03 DSS05.05 DSS06.06 - CCI-001436 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -103357,7 +117077,7 @@ fi - restrict_strategy - name: Detect .rhosts files in users home directories - find: + ansible.builtin.find: paths: - /root - /home @@ -103380,7 +117100,7 @@ fi - restrict_strategy - name: Remove .rhosts files - file: + ansible.builtin.file: path: '{{ item }}' state: absent with_items: '{{ rhosts_locations.files | map(attribute=''path'') | list }}' @@ -103399,7 +117119,7 @@ fi - restrict_strategy - name: Remove /etc/hosts.equiv file - file: + ansible.builtin.file: path: /etc/hosts.equiv state: absent when: '"rsh-server" in ansible_facts.packages' @@ -103429,10 +117149,9 @@ local system. To remove these files, run the following command to delete them from any location: $ sudo find / -name '.shosts' -type f -delete - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002420 - SV-271758r1091986_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002420 + SV-271758r1091986_rule The .shosts files are used to configure host-based authentication for individual users or the system via SSH. Host-based authentication is not sufficient for preventing unauthorized access to the system, as it does not @@ -103453,6 +117172,7 @@ done ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -103616,135 +117336,6 @@ done - - Chat/Messaging Services - The talk software makes it possible for users to send and receive messages -across systems through a terminal session. - - Uninstall talk-server Package - The talk-server package can be removed with the following command: $ sudo yum erase talk-server - - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - R62 - 2.2.4 - 2.2 - The talk software presents a security risk as it uses unencrypted protocols -for communications. Removing the talk-server package decreases the -risk of the accidental (or intentional) activation of talk services. - -# CAUTION: This remediation script will remove talk-server -# from the system, and may remove any packages -# that depend on talk-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "talk-server" ; then -yum remove -y "talk-server" -fi - - - name: Ensure talk-server is removed - package: - name: talk-server - state: absent - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_talk-server_removed - - include remove_talk-server - -class remove_talk-server { - package { 'talk-server': - ensure => 'purged', - } -} - - -package --remove=talk-server - - - - - - - - - - Uninstall talk Package - The talk package contains the client program for the -Internet talk protocol, which allows the user to chat with other users on -different systems. Talk is a communication program which copies lines from one -terminal to the terminal of another user. -The talk package can be removed with the following command: - -$ sudo yum erase talk - - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - R62 - 2.2.4 - 2.2 - The talk software presents a security risk as it uses unencrypted protocols -for communications. Removing the talk package decreases the -risk of the accidental (or intentional) activation of talk client program. - -# CAUTION: This remediation script will remove talk -# from the system, and may remove any packages -# that depend on talk. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "talk" ; then -yum remove -y "talk" -fi - - - name: Ensure talk is removed - package: - name: talk - state: absent - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_talk_removed - - include remove_talk - -class remove_talk { - package { 'talk': - ensure => 'purged', - } -} - - -package --remove=talk - - - - - - - - - Telnet The telnet protocol does not provide confidentiality or integrity @@ -103774,7 +117365,6 @@ $ sudo yum erase telnet-server DSS05.03 DSS05.05 DSS06.06 - CCI-000381 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -103855,17 +117445,18 @@ $ sudo yum erase telnet-server PR.PT-3 PR.PT-4 Req-2.2.2 - SRG-OS-000095-GPOS-00049 + SRG-OS-000095-GPOS-00049 R62 A.8.SEC-OL4 + 1409 2.2.4 2.2 - OL09-00-000110 - SV-271458r1091086_rule + OL09-00-000110 + SV-271458r1091086_rule It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or mission objectives. These unnecessary capabilities are often overlooked and therefore may remain -unsecure. They increase the risk to the platform by providing additional +insecure. They increase the risk to the platform by providing additional attack vectors. The telnet service provides an unencrypted remote access service which does @@ -103877,17 +117468,18 @@ Removing the telnet-server package decreases the risk of telnet service's accidental (or intentional) activation. # CAUTION: This remediation script will remove telnet-server -# from the system, and may remove any packages -# that depend on telnet-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnet-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnet-server" ; then yum remove -y "telnet-server" fi - - name: Ensure telnet-server is removed - package: + - name: 'Uninstall telnet-server Package: Ensure telnet-server is removed' + ansible.builtin.package: name: telnet-server state: absent tags: @@ -103905,7 +117497,8 @@ fi - no_reboot_needed - package_telnet-server_removed - include remove_telnet-server + +include remove_telnet-server class remove_telnet-server { package { 'telnet-server': @@ -103914,6 +117507,7 @@ class remove_telnet-server { } + package --remove=telnet-server @@ -103941,6 +117535,7 @@ the telnet protocol. A.14.1.2 A.14.1.3 R62 + 1409 2.2.4 2.2 The telnet protocol is insecure and unencrypted. The use @@ -103949,17 +117544,18 @@ to steal credentials. The ssh package provides an encrypted session and stronger security and is included in Oracle Linux 9. # CAUTION: This remediation script will remove telnet -# from the system, and may remove any packages -# that depend on telnet. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnet. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnet" ; then yum remove -y "telnet" fi - - name: Ensure telnet is removed - package: + - name: 'Remove telnet Clients: Ensure telnet is removed' + ansible.builtin.package: name: telnet state: absent tags: @@ -103973,7 +117569,8 @@ fi - no_reboot_needed - package_telnet_removed - include remove_telnet + +include remove_telnet class remove_telnet { package { 'telnet': @@ -103982,6 +117579,7 @@ class remove_telnet { } + package --remove=telnet @@ -104122,6 +117720,7 @@ telnet is not created automatically, therefore it might have different names.PR.IP-1 PR.PT-3 PR.PT-4 + 1409 The telnet protocol uses unencrypted network communication, which means that data from the login session, including passwords and all other information transmitted during the session, can be stolen by eavesdroppers on the network. The telnet protocol is also subject to @@ -104169,97 +117768,54 @@ fi - no_reboot_needed - service_telnet_disabled -- name: Disable telnet Service - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable telnet Service - Disable service telnet + block: + + - name: Disable telnet Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable telnet Service - Ensure telnet.service is Masked + ansible.builtin.systemd: + name: telnet.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("telnet.service", multiline=True) + + - name: Unit Socket Exists - telnet.socket + ansible.builtin.command: systemctl -q list-unit-files telnet.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable telnet Service - Disable Socket telnet + ansible.builtin.systemd: + name: telnet.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("telnet.socket", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + - special_service_block when: ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Disable telnet Service - Ensure telnet.service is Masked - ansible.builtin.systemd: - name: telnet.service - state: stopped - enabled: false - masked: true - when: - - ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("telnet.service", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Unit Socket Exists - telnet.socket - ansible.builtin.command: systemctl -q list-unit-files telnet.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Disable telnet Service - Disable Socket telnet - ansible.builtin.systemd: - name: telnet.socket - enabled: false - state: stopped - masked: true - when: - - ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("telnet.socket", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled include disable_telnet @@ -104274,6 +117830,10 @@ class disable_telnet { [customizations.services] masked = ["telnet"] + + + + @@ -104317,7 +117877,6 @@ found. DSS05.03 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -104391,34 +117950,35 @@ found. PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R62 A.8.SEC-OL4 2.2.4 2.2 - OL09-00-000135 - SV-271463r1091101_rule + OL09-00-000135 + SV-271463r1091101_rule Removing the tftp-server package decreases the risk of the accidental (or intentional) activation of tftp services. If TFTP is required for operational support (such as transmission of router configurations), its use must be documented with the Information Systems -Securty Manager (ISSM), restricted to only authorized personnel, and have +Security Manager (ISSM), restricted to only authorized personnel, and have access control rules established. # CAUTION: This remediation script will remove tftp-server -# from the system, and may remove any packages -# that depend on tftp-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on tftp-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "tftp-server" ; then yum remove -y "tftp-server" fi - - name: Ensure tftp-server is removed - package: + - name: 'Uninstall tftp-server Package: Ensure tftp-server is removed' + ansible.builtin.package: name: tftp-server state: absent tags: @@ -104435,7 +117995,8 @@ fi - no_reboot_needed - package_tftp-server_removed - include remove_tftp-server + +include remove_tftp-server class remove_tftp-server { package { 'tftp-server': @@ -104444,6 +118005,7 @@ class remove_tftp-server { } + package --remove=tftp-server @@ -104459,8 +118021,7 @@ package --remove=tftp-server typically used to automatically transfer configuration or boot files between systems. TFTP does not support authentication and can be easily hacked. The package tftp is a client program that allows for connections to a tftp server. - CCI-000197 - SRG-OS-000074-GPOS-00042 + SRG-OS-000074-GPOS-00042 R62 2.2.4 2.2 @@ -104469,17 +118030,18 @@ for TFTP (such as a boot server). In that case, use extreme caution when configu the services. # CAUTION: This remediation script will remove tftp -# from the system, and may remove any packages -# that depend on tftp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on tftp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "tftp" ; then yum remove -y "tftp" fi - - name: Ensure tftp is removed - package: + - name: 'Remove tftp Daemon: Ensure tftp is removed' + ansible.builtin.package: name: tftp state: absent tags: @@ -104492,7 +118054,8 @@ fi - no_reboot_needed - package_tftp_removed - include remove_tftp + +include remove_tftp class remove_tftp { package { 'tftp': @@ -104501,6 +118064,7 @@ class remove_tftp { } + package --remove=tftp @@ -104510,249 +118074,265 @@ package --remove=tftp - - Ensure tftp Daemon Uses Secure Mode + + Ensure tftp systemd Service Uses Secure Mode If running the Trivial File Transfer Protocol (TFTP) service is necessary, it should be configured to change its root directory at startup. To do so, find the path for the tftp systemd service: -$ sudo systemctl show tftp | grep FragmentPath= -FragmentPath=/etc/systemd/system/tftp.service +$ sudo systemctl show tftp | grep ExecStart= +ExecStart={ path=/usr/sbin/in.tftpd ; argv[]=/usr/sbin/in.tftpd -s /var/lib/tftpboot ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }e + and ensure the ExecStart line on that file includes the -s option with a subdirectory: ExecStart=/usr/sbin/in.tftpd -s - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-000366 - 4.3.3.5.1 - 4.3.3.5.2 - 4.3.3.5.3 - 4.3.3.5.4 - 4.3.3.5.5 - 4.3.3.5.6 - 4.3.3.5.7 - 4.3.3.5.8 - 4.3.3.6.1 - 4.3.3.6.2 - 4.3.3.6.3 - 4.3.3.6.4 - 4.3.3.6.5 - 4.3.3.6.6 - 4.3.3.6.7 - 4.3.3.6.8 - 4.3.3.6.9 - 4.3.3.7.1 - 4.3.3.7.2 - 4.3.3.7.3 - 4.3.3.7.4 - 4.3.4.3.2 - 4.3.4.3.3 - SR 1.1 - SR 1.10 - SR 1.11 - SR 1.12 - SR 1.13 - SR 1.2 - SR 1.3 - SR 1.4 - SR 1.5 - SR 1.6 - SR 1.7 - SR 1.8 - SR 1.9 - SR 2.1 - SR 2.2 - SR 2.3 - SR 2.4 - SR 2.5 - SR 2.6 - SR 2.7 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.1.3 - A.13.2.1 - A.13.2.3 - A.13.2.4 - A.14.1.2 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.1.2 - A.6.2.1 - A.6.2.2 - A.7.1.1 - A.7.1.2 - A.7.3.1 - A.8.2.2 - A.8.2.3 - A.9.1.1 - A.9.1.2 - A.9.2.3 - A.9.4.1 - A.9.4.4 - A.9.4.5 - CM-6(b) - AC-6 - CM-7(a) - PR.AC-3 - PR.AC-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-002426 - SV-271764r1092004_rule + IA-5 (1) (c) + SRG-OS-000074-GPOS-00042 + OL09-00-002426 + SV-271764r1092004_rule Using the -s option causes the TFTP service to only serve files from the given directory. Serving files from an intentionally-specified directory reduces the risk of sharing files which should remain private. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q tftp-server; then var_tftpd_secure_directory='' -if grep -q 'server_args' /etc/xinetd.d/tftp; then - sed -i -E "s;^([[:blank:]]*server_args[[:blank:]]+=[[:blank:]]+.*?)(-s[[:blank:]]+[[:graph:]]+)*(.*)$;\1 -s $var_tftpd_secure_directory \3;" /etc/xinetd.d/tftp +DROPIN_DIR="/etc/systemd/system/tftp.service.d" +DROPIN_FILE="$DROPIN_DIR/10-ssg-hardening.conf" +TFTP_SERVICE_FILE="/usr/lib/systemd/system/tftp.service" +REGEX_TFTP_SERVICE_FILE="^\s*ExecStart\s*=\s*/\S+\s+-s\s+(/\S+).*$" +REGEX_DROP_IN="(?s)\s*ExecStart=\s*.*(\s*ExecStart=\s*/\S+\s+-s\s+/\S+.*)" + +# Remove bad configuration in drop-ins +if [ -d "$DROPIN_DIR" ]; then + for override in "$DROPIN_DIR"/*.conf; do + if [ -f "$override" ] && ! grep -qPzo "$REGEX_DROP_IN" "$override"; then + sed -i '/^[[:space:]]*ExecStart=/ s/^/#/' "$override" + fi + done +fi + +if [ -d "$DROPIN_DIR" ] && grep -qPzor "$REGEX_DROP_IN" "$DROPIN_DIR"; then + exit 0 +elif [ ! -d "$DROPIN_DIR" ] && grep -qE "$REGEX_TFTP_SERVICE_FILE" "$TFTP_SERVICE_FILE"; then + exit 0 else - echo "server_args = -s $var_tftpd_secure_directory" >> /etc/xinetd.d/tftp + mkdir -p "$DROPIN_DIR" + + cat > "$DROPIN_FILE" << EOF +[Service] +# clear any existing ExecStart in the original unit +ExecStart= +ExecStart=/usr/sbin/in.tftpd -s $var_tftpd_secure_directory +EOF + systemctl daemon-reload + systemctl restart tftp.service fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd - name: XCCDF Value var_tftpd_secure_directory # promote to variable set_fact: var_tftpd_secure_directory: !!str tags: - always -- name: Find out if the file exists and contains the line configuring server arguments - find: - path: /etc/xinetd.d - patterns: tftp - contains: ^[\s]+server_args.*$ - register: tftpd_secure_config_line +- name: Ensure tftp systemd Service Uses Secure Mode - Find valid drop-ins + ansible.builtin.find: + paths: /etc/systemd/system/tftp.service.d + patterns: '*.conf' + contains: ^\s*ExecStart\s*=\s*/\S+\s+-s\s+/\S+$ + register: valid_dropins + failed_when: false when: '"tftp-server" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd -- name: Ensure that TFTP server is configured to start with secure directory - lineinfile: - path: /etc/xinetd.d/tftp - regexp: ^[\s]*(server_args[\s]+=[\s]+.*?)(-s[\s]+[/\.\w]+)*(.*)$ - line: \1 -s {{ var_tftpd_secure_directory }} \3 - state: present - backrefs: true - when: - - '"tftp-server" in ansible_facts.packages' - - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched > 0 +- name: Ensure tftp systemd Service Uses Secure Mode - Find all drop-in files + ansible.builtin.find: + paths: /etc/systemd/system/tftp.service.d + patterns: '*.conf' + contains: ^\s*ExecStart\s*=.*$ + file_type: file + register: all_dropins + failed_when: false + when: '"tftp-server" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd -- name: Insert correct config line to start TFTP server with secure directory - lineinfile: - path: /etc/xinetd.d/tftp - line: server_args = -s {{ var_tftpd_secure_directory }} - state: present - create: true - when: - - '"tftp-server" in ansible_facts.packages' - - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched == 0 +- name: Ensure tftp systemd Service Uses Secure Mode - Get invalid drop-ins + ansible.builtin.set_fact: + invalid_dropins: '{{ all_dropins.files | rejectattr(''path'', ''in'', valid_dropins.files + | map(attribute=''path'') | list) | map(attribute=''path'') | list }}' + when: '"tftp-server" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Comment all ExecStart in invalid + drop-ins + ansible.builtin.lineinfile: + path: '{{ item }}' + regexp: ^\s*ExecStart\s*=.* + state: absent + loop: '{{ invalid_dropins }}' + when: + - '"tftp-server" in ansible_facts.packages' + - invalid_dropins | length > 0 + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Check if a valid drop-in exists + ansible.builtin.set_fact: + tftp_config_valid: '{{ (valid_dropins.matched | default(0)) > 0 }}' + when: '"tftp-server" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Check if tftp.service contains + valid ExecStart + ansible.builtin.find: + paths: /usr/lib/systemd/system + patterns: tftp.service + contains: ^\s*ExecStart\s*=\s*/\S+\s+-s\s+/\S+ + register: valid_tftp_service + when: + - '"tftp-server" in ansible_facts.packages' + - not tftp_config_valid + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Check if a valid tftp.service + exists + ansible.builtin.set_fact: + original_valid: '{{ (valid_tftp_service.matched | default(0)) > 0 }}' + when: + - '"tftp-server" in ansible_facts.packages' + - not tftp_config_valid + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Recalculate global config validity + ansible.builtin.set_fact: + tftp_config_valid: '{{ tftp_config_valid or original_valid | default(false) }}' + when: '"tftp-server" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Remediate only if necessary + block: + + - name: Ensure drop-in directory exists + ansible.builtin.file: + path: /etc/systemd/system/tftp.service.d + state: directory + + - name: Deploy 10-ssg-hardening.conf drop-in + ansible.builtin.copy: + dest: /etc/systemd/system/tftp.service.d/10-ssg-hardening.conf + content: |- + [Service] + # clear any existing ExecStart in the original unit + ExecStart= + ExecStart=/usr/sbin/in.tftpd -s {{ var_tftpd_secure_directory }} + + - name: Reload systemd and restart tftp service + ansible.builtin.systemd: + daemon_reload: true + name: tftp + state: restarted + enabled: true + when: + - '"tftp-server" in ansible_facts.packages' + - not tftp_config_valid + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd - - + - + @@ -104776,21 +118356,23 @@ and removed. The squid package can be removed with the following command: $ sudo yum erase squid A.8.SEC-OL4 + 1409 If there is no need to make the proxy server software available, removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove squid -# from the system, and may remove any packages -# that depend on squid. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on squid. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "squid" ; then yum remove -y "squid" fi - - name: Ensure squid is removed - package: + - name: 'Uninstall squid Package: Ensure squid is removed' + ansible.builtin.package: name: squid state: absent tags: @@ -104801,7 +118383,8 @@ fi - package_squid_removed - unknown_severity - include remove_squid + +include remove_squid class remove_squid { package { 'squid': @@ -104810,6 +118393,7 @@ class remove_squid { } + package --remove=squid @@ -104825,6 +118409,7 @@ package --remove=squid The squid service can be disabled with the following command: $ sudo systemctl mask --now squid.service + 1409 Running proxy server software provides a network-based avenue of attack, and should be removed if not needed. @@ -104864,73 +118449,48 @@ fi - service_squid_disabled - unknown_severity -- name: Disable Squid - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Squid - Disable service squid + block: + + - name: Disable Squid - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Squid - Ensure squid.service is Masked + ansible.builtin.systemd: + name: squid.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("squid.service", multiline=True) + + - name: Unit Socket Exists - squid.socket + ansible.builtin.command: systemctl -q list-unit-files squid.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Squid - Disable Socket squid + ansible.builtin.systemd: + name: squid.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("squid.socket", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - special_service_block + - unknown_severity when: ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Disable Squid - Ensure squid.service is Masked - ansible.builtin.systemd: - name: squid.service - state: stopped - enabled: false - masked: true - when: - - ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("squid.service", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Unit Socket Exists - squid.socket - ansible.builtin.command: systemctl -q list-unit-files squid.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Disable Squid - Disable Socket squid - ansible.builtin.systemd: - name: squid.socket - enabled: false - state: stopped - masked: true - when: - - ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("squid.socket", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity include disable_squid @@ -104945,6 +118505,10 @@ class disable_squid { [customizations.services] masked = ["squid"] + + + + @@ -104968,8 +118532,7 @@ The rngd service can be enabled with the following comman For Oracle Linux 9 running with kernel FIPS mode enabled this rule is not applicable. The in-kernel deterministic random bit generator (DRBG) is used in FIPS mode instead. Consequently, the rngd service can't be started in FIPS mode. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 The rngd service feeds random data from hardware device to kernel random device. @@ -105002,7 +118565,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the Hardware RNG Entropy Gatherer Service - Enable Service rngd @@ -105013,7 +118576,6 @@ fi masked: false when: - '"rng-tools" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -105021,6 +118583,8 @@ fi - low_severity - no_reboot_needed - service_rngd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_rngd @@ -105035,6 +118599,10 @@ class enable_rngd { [customizations.services] enabled = ["rngd"] + + + + @@ -105067,7 +118635,6 @@ and removed. 8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -105085,9 +118652,9 @@ and removed. CM-7(b) CM-6(a) PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-000140 - SV-271464r1092459_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000140 + SV-271464r1092459_rule Routing software is typically used on routers to exchange network topology information with other routers. If routing software is used when not required, system network information may be unnecessarily transmitted across the network. @@ -105096,17 +118663,18 @@ If there is no need to make the router software available, removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove quagga -# from the system, and may remove any packages -# that depend on quagga. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on quagga. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "quagga" ; then yum remove -y "quagga" fi - - name: Ensure quagga is removed - package: + - name: 'Uninstall quagga Package: Ensure quagga is removed' + ansible.builtin.package: name: quagga state: absent tags: @@ -105121,7 +118689,8 @@ fi - no_reboot_needed - package_quagga_removed - include remove_quagga + +include remove_quagga class remove_quagga { package { 'quagga': @@ -105130,6 +118699,7 @@ class remove_quagga { } + package --remove=quagga @@ -105170,17 +118740,18 @@ removing the package provides a safeguard against its activation. # CAUTION: This remediation script will remove net-snmp -# from the system, and may remove any packages -# that depend on net-snmp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on net-snmp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "net-snmp" ; then yum remove -y "net-snmp" fi - - name: Ensure net-snmp is removed - package: + - name: 'Uninstall net-snmp Package: Ensure net-snmp is removed' + ansible.builtin.package: name: net-snmp state: absent tags: @@ -105193,7 +118764,8 @@ fi - package_net-snmp_removed - unknown_severity - include remove_net-snmp + +include remove_net-snmp class remove_net-snmp { package { 'net-snmp': @@ -105202,6 +118774,7 @@ class remove_net-snmp { } + package --remove=net-snmp @@ -105257,73 +118830,48 @@ fi - no_reboot_needed - service_snmpd_disabled -- name: Disable snmpd Service - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable snmpd Service - Disable service snmpd + block: + + - name: Disable snmpd Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable snmpd Service - Ensure snmpd.service is Masked + ansible.builtin.systemd: + name: snmpd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("snmpd.service", multiline=True) + + - name: Unit Socket Exists - snmpd.socket + ansible.builtin.command: systemctl -q list-unit-files snmpd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable snmpd Service - Disable Socket snmpd + ansible.builtin.systemd: + name: snmpd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("snmpd.socket", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + - special_service_block when: ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled - -- name: Disable snmpd Service - Ensure snmpd.service is Masked - ansible.builtin.systemd: - name: snmpd.service - state: stopped - enabled: false - masked: true - when: - - ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("snmpd.service", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled - -- name: Unit Socket Exists - snmpd.socket - ansible.builtin.command: systemctl -q list-unit-files snmpd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled - -- name: Disable snmpd Service - Disable Socket snmpd - ansible.builtin.systemd: - name: snmpd.socket - enabled: false - state: stopped - masked: true - when: - - ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("snmpd.socket", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled include disable_snmpd @@ -105338,6 +118886,10 @@ class disable_snmpd { [customizations.services] masked = ["snmpd"] + + + + @@ -105387,7 +118939,6 @@ detailed documentation is available from its website, https://www.openssh.com. Its server program is called sshd and provided by the RPM package openssh-server. - SSH enabled firewalld zone Specify firewalld zone to enable SSH service. This value is used only for remediation purposes. @@ -105423,11 +118974,13 @@ Its server program is called sshd and provided by the RPM that are used for data integrity protection by the SSH server. hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 hmac-sha2-512,hmac-sha2-256,hmac-sha1,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-256-etm@openssh.com + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 SSH session Idle time @@ -105474,12 +119027,15 @@ A value of 2 indicates that OpenSSH server package is required by the policy.hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com + -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 SSH Max Sessions Count @@ -105508,44 +119064,24 @@ A value of 2 indicates that OpenSSH server package is required by the policy. $ sudo yum install openssh-clients - CCI-000366 FIA_UAU.5 FTP_ITC_EXT.1 FCS_SSH_EXT.1 FCS_SSHC_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-000260 - SV-271488r1091176_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000260 + SV-271488r1091176_rule This package includes utilities to make encrypted connections and transfer files securely to SSH servers. - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - + if ! rpm -q --quiet "openssh-clients" ; then yum install -y "openssh-clients" fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - name: Gather the package facts - package_facts: - manager: auto - tags: - - DISA-STIG-OL09-00-000260 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-clients_installed - -- name: Ensure openssh-clients is installed - package: + - name: Ensure openssh-clients is installed + ansible.builtin.package: name: openssh-clients state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000260 - enable_strategy @@ -105593,10 +119129,6 @@ $ sudo yum install openssh-server DSS05.07 DSS06.02 DSS06.06 - CCI-002420 - CCI-002421 - CCI-002418 - CCI-002422 SR 3.1 SR 3.8 SR 4.1 @@ -105632,15 +119164,16 @@ $ sudo yum install openssh-server FTP_ITC_EXT.1 FCS_SSH_EXT.1 FCS_SSHS_EXT.1 - SRG-OS-000423-GPOS-00187 - SRG-OS-000424-GPOS-00188 - SRG-OS-000425-GPOS-00189 - SRG-OS-000426-GPOS-00190 - OL09-00-000250 - SV-271482r1091158_rule + SRG-OS-000423-GPOS-00187 + SRG-OS-000424-GPOS-00188 + SRG-OS-000425-GPOS-00189 + SRG-OS-000426-GPOS-00190 + OL09-00-000250 + SV-271482r1091158_rule Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -105666,7 +119199,7 @@ fi - package_openssh-server_installed - name: Ensure openssh-server is installed - package: + ansible.builtin.package: name: openssh-server state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -105713,39 +119246,22 @@ $ sudo yum erase openssh-server Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered. - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - + # CAUTION: This remediation script will remove openssh-server -# from the system, and may remove any packages -# that depend on openssh-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on openssh-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "openssh-server" ; then yum remove -y "openssh-server" fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - name: Gather the package facts - package_facts: - manager: auto - tags: - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-server_removed - -- name: Ensure openssh-server is removed - package: + - name: 'Remove the OpenSSH Server Package: Ensure openssh-server is removed' + ansible.builtin.package: name: openssh-server state: absent - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy - low_complexity @@ -105754,7 +119270,8 @@ fi - no_reboot_needed - package_openssh-server_removed - include remove_openssh-server + +include remove_openssh-server class remove_openssh-server { package { 'openssh-server': @@ -105763,6 +119280,7 @@ class remove_openssh-server { } + package --remove=openssh-server @@ -105790,10 +119308,6 @@ The sshd service can be enabled with the following comman 3.1.13 3.5.4 3.13.8 - CCI-002420 - CCI-002421 - CCI-002418 - CCI-002422 SR 3.1 SR 3.8 SR 4.1 @@ -105830,12 +119344,12 @@ The sshd service can be enabled with the following comman SC-8(4) PR.DS-2 PR.DS-5 - SRG-OS-000423-GPOS-00187 - SRG-OS-000424-GPOS-00188 - SRG-OS-000425-GPOS-00189 - SRG-OS-000426-GPOS-00190 - OL09-00-000251 - SV-271483r1091161_rule + SRG-OS-000423-GPOS-00187 + SRG-OS-000424-GPOS-00188 + SRG-OS-000425-GPOS-00189 + SRG-OS-000426-GPOS-00190 + OL09-00-000251 + SV-271483r1091161_rule Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered. @@ -105846,6 +119360,7 @@ of information system components from which information can be transmitted (e.g. mobile devices, notebook computers, printers, copiers, scanners, etc). Communication paths outside the physical protection of a controlled boundary are exposed to the possibility of interception and modification. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -105885,7 +119400,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the OpenSSH Service - Enable Service sshd @@ -105896,7 +119411,6 @@ fi masked: false when: - '"openssh-server" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000251 - NIST-800-171-3.1.13 @@ -105914,6 +119428,8 @@ fi - medium_severity - no_reboot_needed - service_sshd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_sshd @@ -105928,6 +119444,10 @@ class enable_sshd { [customizations.services] enabled = ["sshd"] + + + + @@ -105944,9 +119464,10 @@ This is unusual, as SSH is a common method for encrypted and authenticated remote access. CM-3(6) IA-2(4) - SRG-APP-000185-CTR-000490 - SRG-APP-000141-CTR-000315 + SRG-APP-000185-CTR-000490 + SRG-APP-000141-CTR-000315 + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -105985,77 +119506,50 @@ fi - no_reboot_needed - service_sshd_disabled -- name: Disable SSH Server If Possible - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable SSH Server If Possible - Disable service sshd + block: + + - name: Disable SSH Server If Possible - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable SSH Server If Possible - Ensure sshd.service is Masked + ansible.builtin.systemd: + name: sshd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("sshd.service", multiline=True) + + - name: Unit Socket Exists - sshd.socket + ansible.builtin.command: systemctl -q list-unit-files sshd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable SSH Server If Possible - Disable Socket sshd + ansible.builtin.systemd: + name: sshd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("sshd.socket", multiline=True) + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Disable SSH Server If Possible - Ensure sshd.service is Masked - ansible.builtin.systemd: - name: sshd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("sshd.service", multiline=True) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Unit Socket Exists - sshd.socket - ansible.builtin.command: systemctl -q list-unit-files sshd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Disable SSH Server If Possible - Disable Socket sshd - ansible.builtin.systemd: - name: sshd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("sshd.socket", multiline=True) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled include disable_sshd @@ -106070,6 +119564,10 @@ class disable_sshd { [customizations.services] masked = ["sshd"] + + + + @@ -106081,7 +119579,8 @@ masked = ["sshd"] Verify Group Who Owns SSH Server config file To properly set the group owner of /etc/ssh/sshd_config, run the command: -$ sudo chgrp root /etc/ssh/sshd_config + + $ sudo chgrp root /etc/ssh/sshd_config 12 13 @@ -106095,7 +119594,6 @@ To properly set the group owner of /etc/ssh/sshd_config, DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106122,32 +119620,45 @@ To properly set the group owner of /etc/ssh/sshd_config, A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002507 - SV-271776r1092040_rule + OL09-00-002507 + SV-271776r1092040_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/ssh/sshd_config +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/ssh/sshd_config" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/ssh/sshd_config +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106168,8 +119679,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_sshd_config_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_sshd_config_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002507 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ssh/sshd_config - stat: + ansible.builtin.stat: path: /etc/ssh/sshd_config register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -106185,10 +119712,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/ssh/sshd_config - file: +- name: Ensure group owner on /etc/ssh/sshd_config + ansible.builtin.file: path: /etc/ssh/sshd_config - group: '0' + follow: false + group: '{{ file_groupowner_sshd_config_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -106219,10 +119747,21 @@ group-owned by ssh_keys group. keys are generated post-deployment. R50 If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended -regex '^.*_key$' -exec chgrp -L ssh_keys {} \; +newgroup="" +if getent group "ssh_keys" >/dev/null 2>&1; then + newgroup="ssh_keys" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "ssh_keys is not a defined group on the system" +else +find -P /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended -regex '^.*_key$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106239,9 +119778,40 @@ fi - medium_severity - no_reboot_needed +- name: Check that the ssh_keys group is defined + ansible.builtin.getent: + database: group + key: ssh_keys + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupownership_sshd_private_key_newgroup is undefined + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupownership_sshd_private_key_newgroup variable if ssh_keys + found + ansible.builtin.set_fact: + file_groupownership_sshd_private_key_newgroup: ssh_keys + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["ssh_keys"] is defined + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*_key$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended - -regex "^.*_key$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys + -regextype posix-extended -regex "^.*_key$" register: files_found changed_when: false failed_when: false @@ -106256,9 +119826,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/ssh/ file(s) matching ^.*_key$ - file: + ansible.builtin.file: path: '{{ item }}' - group: ssh_keys + follow: false + group: '{{ file_groupownership_sshd_private_key_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106287,10 +119858,21 @@ keys are generated post-deployment. R50 If a public host key file is modified by an unauthorized user, the SSH service may be compromised. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.pub$' -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.pub$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106307,9 +119889,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupownership_sshd_pub_key_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupownership_sshd_pub_key_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*\.pub$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended - -regex "^.*\.pub$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype + posix-extended -regex "^.*\.pub$" register: files_found changed_when: false failed_when: false @@ -106324,9 +119919,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/ssh/ file(s) matching ^.*\.pub$ - file: + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ file_groupownership_sshd_pub_key_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106350,7 +119946,8 @@ fi Verify Owner on SSH Server config file To properly set the owner of /etc/ssh/sshd_config, run the command: -$ sudo chown root /etc/ssh/sshd_config + + $ sudo chown root /etc/ssh/sshd_config 12 13 @@ -106364,7 +119961,6 @@ To properly set the owner of /etc/ssh/sshd_config, run th DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106391,32 +119987,45 @@ To properly set the owner of /etc/ssh/sshd_config, run th A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002508 - SV-271777r1092043_rule + OL09-00-002508 + SV-271777r1092043_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/ssh/sshd_config +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/ssh/sshd_config" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/ssh/sshd_config +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106437,8 +120046,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_sshd_config_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_sshd_config_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002508 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ssh/sshd_config - stat: + ansible.builtin.stat: path: /etc/ssh/sshd_config register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -106454,10 +120079,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/ssh/sshd_config - file: +- name: Ensure owner on /etc/ssh/sshd_config + ansible.builtin.file: path: /etc/ssh/sshd_config - owner: '0' + follow: false + owner: '{{ file_owner_sshd_config_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -106488,10 +120114,22 @@ by root user. keys are generated post-deployment. R50 If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*_key$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*_key$' -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106508,9 +120146,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_ownership_sshd_private_key_newown variable if represented by + uid + ansible.builtin.set_fact: + file_ownership_sshd_private_key_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*_key$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*_key$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*_key$" register: files_found changed_when: false failed_when: false @@ -106525,9 +120176,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/ssh/ file(s) matching ^.*_key$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_sshd_private_key_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106556,10 +120208,22 @@ keys are generated post-deployment. R50 If a public host key file is modified by an unauthorized user, the SSH service may be compromised. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*\.pub$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*\.pub$' -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106576,9 +120240,21 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_ownership_sshd_pub_key_newown variable if represented by uid + ansible.builtin.set_fact: + file_ownership_sshd_pub_key_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*\.pub$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*\.pub$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*\.pub$" register: files_found changed_when: false failed_when: false @@ -106593,9 +120269,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/ssh/ file(s) matching ^.*\.pub$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_sshd_pub_key_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106633,7 +120310,6 @@ To properly set the permissions of /etc/ssh/sshd_config, DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106660,30 +120336,31 @@ To properly set the permissions of /etc/ssh/sshd_config, A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002509 - SV-271778r1092046_rule + OL09-00-002509 + SV-271778r1092046_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -106711,7 +120388,7 @@ fi - no_reboot_needed - name: Test for existence /etc/ssh/sshd_config - stat: + ansible.builtin.stat: path: /etc/ssh/sshd_config register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -106730,7 +120407,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/ssh/sshd_config - file: + ansible.builtin.file: path: /etc/ssh/sshd_config mode: u-xs,g-xwrs,o-xwrt when: @@ -106760,7 +120437,7 @@ fi Verify Permissions on SSH Server Private *_key Key Files SSH server private keys - files that match the /etc/ssh/*_key glob, have to have restricted permissions. -If those files are owned by the root user and the root group, they have to have the 0600 permission or stricter. +If those files are owned by the root user and the root group, they have to have the 0640 permission or stricter. If they are owned by the root user, but by a dedicated group ssh_keys, they can have the 0640 permission or stricter. Remediation is not possible at bootable container build time because SSH host keys are generated post-deployment. @@ -106778,7 +120455,6 @@ keys are generated post-deployment. DSS06.02 3.1.13 3.13.10 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106805,29 +120481,31 @@ keys are generated post-deployment. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-2.2.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 + 1449 2.2.6 2.2 - OL09-00-002502 - SV-271771r1092025_rule + OL09-00-002502 + SV-271771r1092025_rule If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -106835,7 +120513,7 @@ for keyfile in /etc/ssh/*_key; do test -f "$keyfile" || continue if test root:root = "$(stat -c "%U:%G" "$keyfile")"; then - chmod u-xs,g-xwrs,o-xwrt "$keyfile" + chmod u-xs,g-xws,o-xwrt "$keyfile" elif test root:ssh_keys = "$(stat -c "%U:%G" "$keyfile")"; then chmod u-xs,g-xws,o-xwrt "$keyfile" @@ -106870,7 +120548,7 @@ fi - name: Find root:root-owned keys ansible.builtin.command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" - -type f -group root -perm /u+xs,g+xwrs,o+xwrt + -type f -group root -perm /u+xs,g+xws,o+xwrt register: root_owned_keys changed_when: false failed_when: false @@ -106896,7 +120574,7 @@ fi - name: Set permissions for root:root-owned keys ansible.builtin.file: path: '{{ item }}' - mode: u-xs,g-xwrs,o-xwrt + mode: u-xs,g-xws,o-xwrt state: file with_items: - '{{ root_owned_keys.stdout_lines }}' @@ -107004,7 +120682,6 @@ keys are generated post-deployment. DSS06.02 3.1.13 3.13.10 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -107031,33 +120708,34 @@ keys are generated post-deployment. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-2.2.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002503 - SV-271772r1092028_rule + OL09-00-002503 + SV-271772r1092028_rule If a public host key file is modified by an unauthorized user, the SSH service may be compromised. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype posix-extended -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \; +find -P /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype posix-extended -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -107084,8 +120762,8 @@ fi - no_reboot_needed - name: Find /etc/ssh/ file(s) - command: find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype - posix-extended -regex "^.*\.pub$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type + f -regextype posix-extended -regex "^.*\.pub$" register: files_found changed_when: false failed_when: false @@ -107109,7 +120787,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/ssh/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xws,o-xwt state: file @@ -107154,12 +120832,12 @@ class ssh_public_key_perms { The /etc/ssh/sshd_config.d/50-redhat.conf file must exist as it contains important settings to secure SSH. There is no remediation available for this rule since this file needs to have the correct content for the given system. - CCI-001453 AC-17 (2) - SRG-OS-000250-GPOS-00093 - OL09-00-000252 - SV-271484r1092624_rule + SRG-OS-000250-GPOS-00093 + OL09-00-000252 + SV-271484r1092624_rule The file must exist to configure SSH correctly. + @@ -107179,6 +120857,7 @@ This is unusual, as SSH is a common method for encrypted and authenticated remote access. If inbound SSH connections are not expected, disallowing access to the SSH port will avoid possible exploitation of the port by an attacker. + Configure OpenSSH Client if Necessary @@ -107204,17 +120883,14 @@ the include directive in the main config file lexicographical order of file names. Make sure that there is no file processed before 02-rekey-limit.conf containing definition of RekeyLimit. - CCI-000068 FCS_SSH_EXT.1.8 - SRG-OS-000423-GPOS-00187 - SRG-OS-000033-GPOS-00014 - SRG-OS-000424-GPOS-00188 + SRG-OS-000423-GPOS-00187 + SRG-OS-000033-GPOS-00014 + SRG-OS-000424-GPOS-00188 By decreasing the limit based on the amount of data and enabling time-based limit, effects of potential attacks against encryption keys are limited. - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - + var_ssh_client_rekey_limit_size='' var_ssh_client_rekey_limit_time='' @@ -107246,22 +120922,8 @@ cp "/etc/ssh/ssh_config.d/02-rekey-limit.conf" "/etc/ssh/ssh_config.d/02-rekey-l printf '%s\n' "RekeyLimit $var_ssh_client_rekey_limit_size $var_ssh_client_rekey_limit_time" >> "/etc/ssh/ssh_config.d/02-rekey-limit.conf" # Clean up after ourselves. rm "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - name: Gather the package facts - package_facts: - manager: auto - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - ssh_client_rekey_limit -- name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable + - name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable set_fact: var_ssh_client_rekey_limit_size: !!str tags: @@ -107273,12 +120935,11 @@ fi - always - name: Ensure RekeyLimit is not configured in /etc/ssh/ssh_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/ssh_config create: false regexp: ^\s*RekeyLimit.*$ state: absent - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107288,12 +120949,11 @@ fi - ssh_client_rekey_limit - name: Collect all include config files for ssh client which configure RekeyLimit - find: + ansible.builtin.find: paths: /etc/ssh/ssh_config.d/ contains: ^[\s]*RekeyLimit.*$ patterns: '*.config' register: ssh_config_include_files - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107302,14 +120962,13 @@ fi - no_reboot_needed - ssh_client_rekey_limit -- name: Remove all occurences of RekeyLimit configuration from include config files +- name: Remove all occurrences of RekeyLimit configuration from include config files of ssh client - lineinfile: + ansible.builtin.lineinfile: path: '{{ item }}' regexp: ^[\s]*RekeyLimit.*$ state: absent loop: '{{ ssh_config_include_files.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107320,14 +120979,13 @@ fi - name: Ensure that rekey limit is set to {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time }} in /etc/ssh/ssh_config.d/02-rekey-limit.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/ssh_config.d/02-rekey-limit.conf create: true regexp: ^\s*RekeyLimit.*$ line: RekeyLimit {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time }} state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107352,13 +121010,15 @@ fi You can create such keys with the following command: $ sudo ssh-keygen -n [passphrase] Oracle Linux 9, for certificate-based authentication, must enforce authorized access to the corresponding private key. - CCI-000186 - SRG-OS-000067-GPOS-00035 - OL09-00-000905 - SV-271605r1091527_rule + SRG-OS-000067-GPOS-00035 + OL09-00-000905 + SV-271605r1091527_rule If an unauthorized user obtains access to a private key without a passcode, that user would have unauthorized access to any system where the associated public key has been installed. + + + @@ -107371,6 +121031,7 @@ certain changes should be made to the OpenSSH daemon configuration file /etc/ssh/sshd_config. The following recommendations can be applied to this file. See the sshd_config(5) man page for more detailed information. + SSH RekeyLimit - size Specify the size component of the rekey limit. @@ -107421,11 +121082,10 @@ The following line should be present in /etc/ssh/sshd_configInclude /etc/crypto-policies/back-ends/opensshserver.config There is no automated remediation because recommended action could severely disrupt the system and might not be efficient in fixing the problem. - CCI-001453 AC-17 (2) - SRG-OS-000250-GPOS-00093 - OL09-00-000252 - SV-271484r1092624_rule + SRG-OS-000250-GPOS-00093 + OL09-00-000252 + SV-271484r1092624_rule Without cryptographic integrity protections, information can be altered by unauthorized users without detection. @@ -107445,7 +121105,7 @@ To ensure the SSH timeout occurs precisely when the value of 0 in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: 1 12 13 @@ -107471,9 +121131,6 @@ value of 0 in DSS06.03 DSS06.10 3.1.11 - CCI-000879 - CCI-001133 - CCI-002361 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -107528,12 +121185,12 @@ value of 0 in A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-2(5) AC-12 AC-17(a) @@ -107547,9 +121204,9 @@ value of 0 in PR.AC-7 PR.IP-2 Req-8.1.8 - SRG-OS-000126-GPOS-00066 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 + SRG-OS-000126-GPOS-00066 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 This ensures a user login will be terminated as soon as the ClientAliveInterval is reached. @@ -107564,21 +121221,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "ClientAliveCountMax 0" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "ClientAliveCountMax 0" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -107604,7 +121267,7 @@ fi - sshd_set_keepalive_0 - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -107626,7 +121289,7 @@ fi - sshd_set_keepalive_0 - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*ClientAliveCountMax.*)$ replace: '# \1' @@ -107648,36 +121311,124 @@ fi - restrict_strategy - sshd_set_keepalive_0 +- name: Set SSH Client Alive Count Max to zero - Check if the parameter ClientAliveCountMax + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Set SSH Client Alive Count Max to zero - Check if the parameter ClientAliveCountMax + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+0$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + - name: Set SSH Client Alive Count Max to zero block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter ClientAliveCountMax is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ line: ClientAliveCountMax 0 state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Set SSH Client Alive Count Max to zero - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -107743,8 +121494,6 @@ a keep alive message. DSS06.03 DSS06.10 3.1.11 - CCI-001133 - CCI-002361 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -107799,12 +121548,12 @@ a keep alive message. A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-2(5) AC-12 AC-17(a) @@ -107818,13 +121567,13 @@ a keep alive message. PR.AC-7 PR.IP-2 Req-8.1.8 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 A.5.SEC-OL7 8.2.8 8.2 - OL09-00-002346 - SV-271709r1091839_rule + OL09-00-002346 + SV-271709r1091839_rule This ensures a user login will be terminated as soon as the ClientAliveInterval is reached. @@ -107834,7 +121583,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_set_keepalive='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -107843,21 +121591,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -107891,7 +121645,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -107916,7 +121670,7 @@ fi - sshd_set_keepalive - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*ClientAliveCountMax.*)$ replace: '# \1' @@ -107941,36 +121695,134 @@ fi - restrict_strategy - sshd_set_keepalive +- name: Set SSH Client Alive Count Max - Check if the parameter ClientAliveCountMax + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + +- name: Set SSH Client Alive Count Max - Check if the parameter ClientAliveCountMax + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+{{ var_sshd_set_keepalive + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + - name: Set SSH Client Alive Count Max block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter ClientAliveCountMax is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ line: ClientAliveCountMax {{ var_sshd_set_keepalive }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + +- name: Set SSH Client Alive Count Max - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -108049,9 +121901,6 @@ configuring ClientAliveCountMax in the SSH service configuration.DSS06.03 DSS06.10 3.1.11 - CCI-001133 - CCI-002361 - CCI-002891 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -108100,12 +121949,12 @@ configuring ClientAliveCountMax in the SSH service configuration.A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 CM-6(a) AC-17(a) AC-2(5) @@ -108121,15 +121970,15 @@ configuring ClientAliveCountMax in the SSH service configuration.PR.AC-7 PR.IP-2 Req-8.1.8 - SRG-OS-000126-GPOS-00066 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 - SRG-OS-000395-GPOS-00175 + SRG-OS-000126-GPOS-00066 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 + SRG-OS-000395-GPOS-00175 A.5.SEC-OL7 8.2.8 8.2 - OL09-00-002347 - SV-271710r1092596_rule + OL09-00-002347 + SV-271710r1092596_rule Terminating an idle ssh session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been let unattended. @@ -108140,7 +121989,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then sshd_idle_timeout_value='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -108149,21 +121997,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*ClientAliveInterval/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -108199,7 +122053,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -108226,7 +122080,7 @@ fi - sshd_set_idle_timeout - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*ClientAliveInterval.*)$ replace: '# \1' @@ -108253,36 +122107,140 @@ fi - restrict_strategy - sshd_set_idle_timeout +- name: Set SSH Client Alive Interval - Check if the parameter ClientAliveInterval + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + +- name: Set SSH Client Alive Interval - Check if the parameter ClientAliveInterval + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+{{ sshd_idle_timeout_value + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + - name: Set SSH Client Alive Interval block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveInterval\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter ClientAliveInterval is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + regexp: (?i)(?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ line: ClientAliveInterval {{ sshd_idle_timeout_value }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + +- name: Set SSH Client Alive Interval - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -108328,7 +122286,7 @@ To explicitly disable host-based authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: HostbasedAuthentication no @@ -108353,7 +122311,6 @@ following line in DSS06.03 DSS06.06 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -108405,20 +122362,6 @@ following line in SR 2.6 SR 2.7 SR 7.6 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.12.1.2 A.12.5.1 A.12.6.2 @@ -108433,16 +122376,16 @@ following line in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-3 AC-17(a) CM-7(a) @@ -108453,11 +122396,25 @@ following line in PR.IP-1 PR.PT-3 FIA_UAU.1 - SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00229 + 0421 + 0422 + 0484 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.1 8.3 - OL09-00-002357 - SV-271719r1091869_rule + OL09-00-002357 + SV-271719r1091869_rule SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts. # Remediation is applicable only in certain platforms @@ -108471,21 +122428,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*HostbasedAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "HostbasedAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "HostbasedAuthentication no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -108513,7 +122476,7 @@ fi - restrict_strategy - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -108537,7 +122500,7 @@ fi - restrict_strategy - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*HostbasedAuthentication.*)$ replace: '# \1' @@ -108561,36 +122524,130 @@ fi - no_reboot_needed - restrict_strategy +- name: Disable Host-Based Authentication - Check if the parameter HostbasedAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Host-Based Authentication - Check if the parameter HostbasedAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Disable Host-Based Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter HostbasedAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ line: HostbasedAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Host-Based Authentication - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -108651,15 +122708,12 @@ properly migrated from ifcfg format to NetworkManager key rule won't be able to check the configuration. The migration can be accomplished by nmcli connection migrate command. 3.1.12 - CCI-000382 - 1416 AC-17(a) CM-6(b) CM-7(a) CM-7(b) - SRG-OS-000096-GPOS-00050 - OL09-00-000222 - SV-271471r1091125_rule + SRG-OS-000096-GPOS-00050 + 1416 If inbound SSH connections are expected, adding the SSH port to the proper firewalld zone will allow remote access through the SSH port. # Remediation is applicable only in certain platforms @@ -108674,7 +122728,7 @@ fi firewalld_sshd_zone='' -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then # By default, NetworkManager interfaces are created only once # container image is booted so we do not have information about # what interfaces will be created during container build time. @@ -108700,7 +122754,7 @@ else if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)"; then # TODO: NM (nmcli) now has --offline mode support, and it could operate without NM service. # See: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1183 - # The feature is not quite straighforward (and probably incomplete), though. + # The feature is not quite straightforward (and probably incomplete), though. echo "Not applicable in offline mode. Remediation aborted!" else if systemctl is-active NetworkManager && systemctl is-active firewalld; then @@ -108742,7 +122796,6 @@ fi package_facts: manager: auto tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108770,7 +122823,6 @@ fi - NetworkManager when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108786,10 +122838,8 @@ fi - name: Enable SSH Server firewalld Firewall Exception - Collect facts about system services ansible.builtin.service_facts: null - register: result_services_states when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108811,7 +122861,9 @@ fi ansible.builtin.shell: cmd: nmcli -g UUID,TYPE con | grep -v loopback | awk -F ':' '{ print $1 }' register: result_nmcli_cmd_connections_names + check_mode: false changed_when: false + failed_when: false - name: Enable SSH Server firewalld Firewall Exception - Collect NetworkManager connections zones @@ -108820,20 +122872,27 @@ fi $2}' register: result_nmcli_cmd_connections_zones changed_when: false + failed_when: false with_items: - - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' + - '{{ result_nmcli_cmd_connections_names.stdout_lines | default([]) }}' + when: + - result_nmcli_cmd_connections_names.stdout_lines is defined + - result_nmcli_cmd_connections_names.stdout_lines | length > 0 - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections are assigned to a firewalld zone ansible.builtin.command: cmd: nmcli connection modify {{ item.0 }} connection.zone {{ firewalld_sshd_zone }} - register: result_nmcli_cmd_connections_assignment + register: result_nmcli_cmd_zone_assignment + changed_when: true with_together: - - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' - - '{{ result_nmcli_cmd_connections_zones.results }}' + - '{{ result_nmcli_cmd_connections_names.stdout_lines | default([]) }}' + - '{{ result_nmcli_cmd_connections_zones.stdout_lines | default([]) }}' when: - - item.1.stdout == '--' + - result_nmcli_cmd_connections_zones.stdout_lines is defined + - result_nmcli_cmd_connections_zones.stdout_lines | length > 0 + - item.1.stdout == '--' or item.1.stdout != firewalld_sshd_zone - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections changes are applied @@ -108841,7 +122900,10 @@ fi name: NetworkManager state: restarted when: - - result_nmcli_cmd_connections_assignment is changed + - result_nmcli_cmd_zone_assignment is defined + - result_nmcli_cmd_zone_assignment is changed + - result_nmcli_cmd_zone_assignment.results | selectattr('changed', 'equalto', + true) | list | length > 0 - name: Enable SSH Server firewalld Firewall Exception - Collect firewalld active zones @@ -108849,30 +122911,27 @@ fi cmd: firewall-cmd --get-active-zones | grep -v "^ " | cut -d " " -f 1 register: result_firewall_cmd_zones_names changed_when: false + failed_when: false - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld zones allow SSH - ansible.builtin.command: - cmd: firewall-cmd --permanent --zone={{ item }} --add-service=ssh - register: result_nmcli_cmd_connections_assignment - changed_when: - - '''ALREADY_ENABLED'' not in result_nmcli_cmd_connections_assignment.stderr' + ansible.posix.firewalld: + zone: '{{ item }}' + service: ssh + permanent: true + state: enabled + immediate: true + register: result_firewall_ssh_service_assignment with_items: - - '{{ result_firewall_cmd_zones_names.stdout_lines }}' - - - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld changes - are applied - ansible.builtin.service: - name: firewalld - state: reloaded + - '{{ result_firewall_cmd_zones_names.stdout_lines | default([]) }}' when: - - result_nmcli_cmd_connections_assignment is changed + - result_firewall_cmd_zones_names.stdout_lines is defined + - result_firewall_cmd_zones_names.stdout_lines | length > 0 when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_facts.services['firewalld.service'].state == 'running' - ansible_facts.services['NetworkManager.service'].state == 'running' tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108889,8 +122948,9 @@ fi on services states ansible.builtin.assert: that: - - ansible_facts.services['firewalld.service'].state == 'running' - - ansible_facts.services['NetworkManager.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['firewalld.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['NetworkManager.service'].state + == 'running' fail_msg: - firewalld and NetworkManager services are not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld and NetworkManager @@ -108901,7 +122961,6 @@ fi - Enable SSH Server firewalld Firewall Exception remediation successfully executed when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108953,8 +123012,6 @@ supported is version 2, and line Protocol 2 in DSS06.10 3.1.13 3.5.4 - CCI-000197 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -108997,9 +123054,6 @@ supported is version 2, and line Protocol 2 in SR 5.3 SR 7.1 SR 7.6 - 0487 - 1449 - 1506 A.11.2.6 A.13.1.1 A.13.2.1 @@ -109016,9 +123070,9 @@ supported is version 2, and line Protocol 2 in A.9.3.1 A.9.4.2 A.9.4.3 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 CM-6(a) AC-17(a) AC-17(2) @@ -109030,8 +123084,9 @@ supported is version 2, and line Protocol 2 in PR.AC-6 PR.AC-7 PR.PT-4 - SRG-OS-000074-GPOS-00042 - SRG-OS-000480-GPOS-00227 + SRG-OS-000074-GPOS-00042 + SRG-OS-000480-GPOS-00227 + 1483 SSH protocol version 1 is an insecure implementation of the SSH protocol and has many well-known vulnerability exploits. Exploits of the SSH daemon could provide immediate root access to the system. @@ -109046,21 +123101,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Protocol/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Protocol 2" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Protocol 2" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109087,7 +123148,7 @@ fi - sshd_allow_only_protocol2 - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109110,7 +123171,7 @@ fi - sshd_allow_only_protocol2 - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Protocol.*)$ replace: '# \1' @@ -109133,36 +123194,126 @@ fi - restrict_strategy - sshd_allow_only_protocol2 +- name: Allow Only SSH Protocol 2 - Check if the parameter Protocol is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Protocol"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Allow Only SSH Protocol 2 - Check if the parameter Protocol is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Protocol"| regex_escape }}\s+2$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + - name: Allow Only SSH Protocol 2 block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Protocol\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Protocol\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Protocol"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Protocol is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Protocol"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Protocol"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Protocol\s+ + regexp: (?i)(?i)^\s*{{ "Protocol"| regex_escape }}\s+ line: Protocol 2 state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Allow Only SSH Protocol 2 - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -109208,7 +123359,6 @@ a user has successfully authenticated, add or correct the following line in the BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109229,9 +123379,9 @@ a user has successfully authenticated, add or correct the following line in the CM-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00227 - OL09-00-002355 - SV-271717r1091863_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002355 + SV-271717r1091863_rule If compression is allowed in an SSH connection prior to authentication, vulnerabilities in the compression software could result in compromise of the system from an unauthenticated connection, potentially with root privileges. @@ -109241,7 +123391,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_disable_compression='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -109250,21 +123399,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Compression/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Compression $var_sshd_disable_compression" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Compression $var_sshd_disable_compression" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109293,7 +123448,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109313,7 +123468,7 @@ fi - sshd_disable_compression - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Compression.*)$ replace: '# \1' @@ -109333,36 +123488,119 @@ fi - restrict_strategy - sshd_disable_compression +- name: Disable Compression Or Set Compression to delayed - Check if the parameter + Compression is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Compression"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + +- name: Disable Compression Or Set Compression to delayed - Check if the parameter + Compression is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Compression"| regex_escape }}\s+{{ var_sshd_disable_compression + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + - name: Disable Compression Or Set Compression to delayed block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Compression\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Compression\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Compression"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Compression is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Compression"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Compression"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Compression\s+ + regexp: (?i)(?i)^\s*{{ "Compression"| regex_escape }}\s+ line: Compression {{ var_sshd_disable_compression }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + +- name: Disable Compression Or Set Compression to delayed - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002355 @@ -109397,7 +123635,7 @@ To explicitly disallow SSH login from accounts with empty passwords, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitEmptyPasswords no @@ -109428,8 +123666,6 @@ should prevent users from being able to assign themselves empty passwords.DSS06.06 3.1.1 3.1.5 - CCI-000766 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109523,13 +123759,14 @@ should prevent users from being able to assign themselves empty passwords.PR.PT-3 FIA_UAU.1 Req-2.2.4 - SRG-OS-000106-GPOS-00053 - SRG-OS-000480-GPOS-00229 - SRG-OS-000480-GPOS-00227 + SRG-OS-000106-GPOS-00053 + SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00227 + 1546 2.2.6 2.2 - OL09-00-002343 - SV-271706r1091830_rule + OL09-00-002343 + SV-271706r1091830_rule Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere. @@ -109544,21 +123781,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitEmptyPasswords/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitEmptyPasswords no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitEmptyPasswords no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109587,7 +123830,7 @@ fi - sshd_disable_empty_passwords - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109612,7 +123855,7 @@ fi - sshd_disable_empty_passwords - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitEmptyPasswords.*)$ replace: '# \1' @@ -109637,36 +123880,133 @@ fi - restrict_strategy - sshd_disable_empty_passwords +- name: Disable SSH Access via Empty Passwords - Check if the parameter PermitEmptyPasswords + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Disable SSH Access via Empty Passwords - Check if the parameter PermitEmptyPasswords + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + - name: Disable SSH Access via Empty Passwords block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitEmptyPasswords is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + regexp: (?i)(?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ line: PermitEmptyPasswords no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Disable SSH Access via Empty Passwords - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -109706,7 +124046,7 @@ configuration is used if no value is set for GSSAPIAuthentication/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: GSSAPIAuthentication no @@ -109718,8 +124058,6 @@ To explicitly disable GSSAPI authentication, add or correct the following line i BAI10.03 BAI10.05 3.1.12 - CCI-000366 - CCI-001813 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109729,9 +124067,6 @@ To explicitly disable GSSAPI authentication, add or correct the following line i 4.3.4.3.2 4.3.4.3.3 SR 7.6 - 0418 - 1055 - 1402 A.12.1.2 A.12.5.1 A.12.6.2 @@ -109745,10 +124080,13 @@ To explicitly disable GSSAPI authentication, add or correct the following line i PR.IP-1 FTP_ITC_EXT.1 FCS_SSH_EXT.1.2 - SRG-OS-000364-GPOS-00151 - SRG-OS-000480-GPOS-00227 - OL09-00-002341 - SV-271704r1091824_rule + SRG-OS-000364-GPOS-00151 + SRG-OS-000480-GPOS-00227 + 0418 + 1055 + 1402 + OL09-00-002341 + SV-271704r1091824_rule GSSAPI authentication is used to provide additional authentication mechanisms to applications. Allowing GSSAPI authentication through SSH exposes the system's GSSAPI to remote hosts, increasing the attack surface of the system. @@ -109763,21 +124101,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "GSSAPIAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "GSSAPIAuthentication no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109801,7 +124145,7 @@ fi - sshd_disable_gssapi_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109821,7 +124165,7 @@ fi - sshd_disable_gssapi_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*GSSAPIAuthentication.*)$ replace: '# \1' @@ -109841,36 +124185,118 @@ fi - restrict_strategy - sshd_disable_gssapi_auth +- name: Disable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Disable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + - name: Disable GSSAPI Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter GSSAPIAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ line: GSSAPIAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Disable GSSAPI Authentication - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002341 @@ -109905,7 +124331,7 @@ The appropriate configuration is used if no value is set for Kerberos To explicitly disable Kerberos authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: KerberosAuthentication no @@ -109917,8 +124343,6 @@ To explicitly disable Kerberos authentication, add or correct the following line BAI10.03 BAI10.05 3.1.12 - CCI-000366 - CCI-001813 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109928,20 +124352,6 @@ To explicitly disable Kerberos authentication, add or correct the following line 4.3.4.3.2 4.3.4.3.3 SR 7.6 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.12.1.2 A.12.5.1 A.12.6.2 @@ -109955,10 +124365,23 @@ To explicitly disable Kerberos authentication, add or correct the following line PR.IP-1 FTP_ITC_EXT.1 FCS_SSH_EXT.1.2 - SRG-OS-000364-GPOS-00151 - SRG-OS-000480-GPOS-00227 - OL09-00-002356 - SV-271718r1091866_rule + SRG-OS-000364-GPOS-00151 + SRG-OS-000480-GPOS-00227 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-002356 + SV-271718r1091866_rule Kerberos authentication for SSH is often implemented using GSSAPI. If Kerberos is enabled through SSH, the SSH daemon provides a means of access to the system's Kerberos implementation. @@ -109974,21 +124397,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*KerberosAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "KerberosAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "KerberosAuthentication no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110012,7 +124441,7 @@ fi - sshd_disable_kerb_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110032,7 +124461,7 @@ fi - sshd_disable_kerb_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*KerberosAuthentication.*)$ replace: '# \1' @@ -110052,36 +124481,118 @@ fi - restrict_strategy - sshd_disable_kerb_auth +- name: Disable Kerberos Authentication - Check if the parameter KerberosAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Disable Kerberos Authentication - Check if the parameter KerberosAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + - name: Disable Kerberos Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*KerberosAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter KerberosAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ line: KerberosAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Disable Kerberos Authentication - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002356 @@ -110112,7 +124623,7 @@ authentication mechanisms. To disable PubkeyAuthentication authentication, add o correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PubkeyAuthentication no @@ -110130,21 +124641,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PubkeyAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PubkeyAuthentication no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110162,7 +124679,7 @@ fi - sshd_disable_pubkey_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110176,7 +124693,7 @@ fi - sshd_disable_pubkey_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PubkeyAuthentication.*)$ replace: '# \1' @@ -110190,36 +124707,100 @@ fi - restrict_strategy - sshd_disable_pubkey_auth +- name: Disable PubkeyAuthentication Authentication - Check if the parameter PubkeyAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Disable PubkeyAuthentication Authentication - Check if the parameter PubkeyAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + - name: Disable PubkeyAuthentication Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PubkeyAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ line: PubkeyAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Disable PubkeyAuthentication Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity @@ -110249,7 +124830,7 @@ configuration is used if no value is set for IgnoreRhosts To explicitly disable support for .rhosts files, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: IgnoreRhosts yes @@ -110274,7 +124855,6 @@ To explicitly disable support for .rhosts files, add or correct the following li DSS06.03 DSS06.06 3.1.12 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -110342,11 +124922,12 @@ To explicitly disable support for .rhosts files, add or correct the following li PR.AC-6 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1546 2.2.6 2.2 - OL09-00-002348 - SV-271711r1091845_rule + OL09-00-002348 + SV-271711r1091845_rule SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts. # Remediation is applicable only in certain platforms @@ -110360,21 +124941,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*IgnoreRhosts/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "IgnoreRhosts yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "IgnoreRhosts yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110401,7 +124988,7 @@ fi - sshd_disable_rhosts - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110424,7 +125011,7 @@ fi - sshd_disable_rhosts - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*IgnoreRhosts.*)$ replace: '# \1' @@ -110447,36 +125034,127 @@ fi - restrict_strategy - sshd_disable_rhosts +- name: Disable SSH Support for .rhosts Files - Check if the parameter IgnoreRhosts + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Disable SSH Support for .rhosts Files - Check if the parameter IgnoreRhosts + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + - name: Disable SSH Support for .rhosts Files block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreRhosts\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter IgnoreRhosts is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + regexp: (?i)(?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ line: IgnoreRhosts yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Disable SSH Support for .rhosts Files - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -110525,7 +125203,6 @@ necessary. BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -110546,7 +125223,7 @@ necessary. CM-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere. @@ -110561,21 +125238,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "RhostsRSAAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "RhostsRSAAuthentication no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110598,7 +125281,7 @@ fi - sshd_disable_rhosts_rsa - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110617,7 +125300,7 @@ fi - sshd_disable_rhosts_rsa - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*RhostsRSAAuthentication.*)$ replace: '# \1' @@ -110636,36 +125319,115 @@ fi - restrict_strategy - sshd_disable_rhosts_rsa +- name: Disable SSH Support for Rhosts RSA Authentication - Check if the parameter + RhostsRSAAuthentication is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Disable SSH Support for Rhosts RSA Authentication - Check if the parameter + RhostsRSAAuthentication is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + - name: Disable SSH Support for Rhosts RSA Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter RhostsRSAAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ line: RhostsRSAAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Disable SSH Support for Rhosts RSA Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.12 @@ -110695,7 +125457,7 @@ system directly over a network. To disable root login via SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitRootLogin no @@ -110722,8 +125484,6 @@ To disable root login via SSH, add or correct the following line in DSS06.10 3.1.1 3.1.5 - CCI-000366 - CCI-004045 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -110804,20 +125564,20 @@ To disable root login via SSH, add or correct the following line in A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-6(2) AC-17(a) IA-2 @@ -110833,15 +125593,16 @@ To disable root login via SSH, add or correct the following line in PR.PT-3 FAU_GEN.1 Req-2.2.4 - SRG-OS-000109-GPOS-00056 - SRG-OS-000480-GPOS-00227 - SRG-APP-000148-CTR-000335 - SRG-APP-000190-CTR-000500 + SRG-OS-000109-GPOS-00056 + SRG-OS-000480-GPOS-00227 + SRG-APP-000148-CTR-000335 + SRG-APP-000190-CTR-000500 R33 + 1546 2.2.6 2.2 - OL09-00-002345 - SV-271708r1092594_rule + OL09-00-002345 + SV-271708r1092594_rule Even though the communications channel may be encrypted, an additional layer of security is gained by extending the policy of not logging directly on as root. In addition, logging in with a user-specific account provides individual @@ -110858,21 +125619,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitRootLogin no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitRootLogin no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110904,7 +125671,7 @@ fi - sshd_disable_root_login - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110932,7 +125699,7 @@ fi - sshd_disable_root_login - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitRootLogin.*)$ replace: '# \1' @@ -110960,36 +125727,141 @@ fi - restrict_strategy - sshd_disable_root_login +- name: Disable SSH Root Login - Check if the parameter PermitRootLogin is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Disable SSH Root Login - Check if the parameter PermitRootLogin is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + - name: Disable SSH Root Login block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitRootLogin is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ line: PermitRootLogin no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Disable SSH Root Login - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -111026,7 +125898,7 @@ fi To disable password-based root logins over SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitRootLogin prohibit-password @@ -111051,21 +125923,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitRootLogin prohibit-password" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitRootLogin prohibit-password" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111083,7 +125961,7 @@ fi - sshd_disable_root_password_login - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111097,7 +125975,7 @@ fi - sshd_disable_root_password_login - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitRootLogin.*)$ replace: '# \1' @@ -111111,36 +125989,100 @@ fi - restrict_strategy - sshd_disable_root_password_login +- name: Disable SSH root Login with a Password (Insecure) - Check if the parameter + PermitRootLogin is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Disable SSH root Login with a Password (Insecure) - Check if the parameter + PermitRootLogin is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+prohibit-password$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + - name: Disable SSH root Login with a Password (Insecure) block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitRootLogin is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ line: PermitRootLogin prohibit-password state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Disable SSH root Login with a Password (Insecure) - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity @@ -111164,7 +126106,7 @@ fi To disable TCP forwarding, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: AllowTcpForwarding no @@ -111182,21 +126124,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*AllowTcpForwarding/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "AllowTcpForwarding no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "AllowTcpForwarding no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111216,7 +126164,7 @@ fi - sshd_disable_tcp_forwarding - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111232,7 +126180,7 @@ fi - sshd_disable_tcp_forwarding - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*AllowTcpForwarding.*)$ replace: '# \1' @@ -111248,36 +126196,106 @@ fi - restrict_strategy - sshd_disable_tcp_forwarding +- name: Disable SSH TCP Forwarding - Check if the parameter AllowTcpForwarding is + configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Disable SSH TCP Forwarding - Check if the parameter AllowTcpForwarding is + configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + - name: Disable SSH TCP Forwarding block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + create: false + regexp: (?i)(?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter AllowTcpForwarding is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + regexp: (?i)(?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ line: AllowTcpForwarding no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Disable SSH TCP Forwarding - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -111306,7 +126324,7 @@ systems public keys is available. This should be disabled. To ensure this behavior is disabled, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: IgnoreUserKnownHosts yes @@ -111318,7 +126336,6 @@ To ensure this behavior is disabled, add or correct the following line in BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -111339,9 +126356,10 @@ To ensure this behavior is disabled, add or correct the following line in CM-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00227 - OL09-00-002349 - SV-271712r1091848_rule + SRG-OS-000480-GPOS-00227 + 1546 + OL09-00-002349 + SV-271712r1091848_rule Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere. @@ -111356,21 +126374,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "IgnoreUserKnownHosts yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "IgnoreUserKnownHosts yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111394,7 +126418,7 @@ fi - sshd_disable_user_known_hosts - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111414,7 +126438,7 @@ fi - sshd_disable_user_known_hosts - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*IgnoreUserKnownHosts.*)$ replace: '# \1' @@ -111434,36 +126458,118 @@ fi - restrict_strategy - sshd_disable_user_known_hosts +- name: Disable SSH Support for User Known Hosts - Check if the parameter IgnoreUserKnownHosts + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Disable SSH Support for User Known Hosts - Check if the parameter IgnoreUserKnownHosts + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + - name: Disable SSH Support for User Known Hosts block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter IgnoreUserKnownHosts is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + regexp: (?i)(?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ line: IgnoreUserKnownHosts yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Disable SSH Support for User Known Hosts - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002349 @@ -111500,17 +126606,17 @@ configuration is used if no value is set for X11Forwarding/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: X11Forwarding no - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 0484 2.2.6 2.2 - OL09-00-002350 - SV-271713r1091851_rule + OL09-00-002350 + SV-271713r1091851_rule Disable X11 forwarding unless there is an operational requirement to use X11 applications directly. There is a small risk that the remote X11 servers of users who are logged in via SSH with X11 forwarding could be compromised by @@ -111527,21 +126633,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "X11Forwarding no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "X11Forwarding no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111563,7 +126675,7 @@ fi - sshd_disable_x11_forwarding - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111581,7 +126693,7 @@ fi - sshd_disable_x11_forwarding - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*X11Forwarding.*)$ replace: '# \1' @@ -111599,36 +126711,111 @@ fi - restrict_strategy - sshd_disable_x11_forwarding +- name: Disable X11 Forwarding - Check if the parameter X11Forwarding is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Disable X11 Forwarding - Check if the parameter X11Forwarding is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + - name: Disable X11 Forwarding block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter X11Forwarding is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ line: X11Forwarding no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Disable X11 Forwarding - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002350 @@ -111660,7 +126847,7 @@ configuration is used if no value is set for PermitUserEnvironment/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitUserEnvironment no @@ -111673,7 +126860,6 @@ To explicitly disable Environment options, add or correct the following BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -111695,11 +126881,12 @@ To explicitly disable Environment options, add or correct the following CM-6(a) PR.IP-1 Req-2.2.4 - SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00229 + 1546 2.2.6 2.2 - OL09-00-002358 - SV-271720r1091872_rule + OL09-00-002358 + SV-271720r1091872_rule SSH environment options potentially allow users to bypass access restriction in some configurations. # Remediation is applicable only in certain platforms @@ -111713,21 +126900,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitUserEnvironment/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitUserEnvironment no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitUserEnvironment no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111755,7 +126948,7 @@ fi - sshd_do_not_permit_user_env - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111779,7 +126972,7 @@ fi - sshd_do_not_permit_user_env - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitUserEnvironment.*)$ replace: '# \1' @@ -111803,36 +126996,130 @@ fi - restrict_strategy - sshd_do_not_permit_user_env +- name: Do Not Allow SSH Environment Options - Check if the parameter PermitUserEnvironment + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Do Not Allow SSH Environment Options - Check if the parameter PermitUserEnvironment + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + - name: Do Not Allow SSH Environment Options block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitUserEnvironment is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + regexp: (?i)(?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ line: PermitUserEnvironment no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Do Not Allow SSH Environment Options - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -111862,12 +127149,12 @@ fi Enable GSSAPI Authentication - Sites setup to use Kerberos or other GSSAPI Authenticaion require setting + Sites setup to use Kerberos or other GSSAPI Authentication require setting sshd to accept this authentication. To enable GSSAPI authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: GSSAPIAuthentication yes @@ -111890,21 +127177,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "GSSAPIAuthentication yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "GSSAPIAuthentication yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111922,7 +127215,7 @@ fi - sshd_enable_gssapi_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111936,7 +127229,7 @@ fi - sshd_enable_gssapi_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*GSSAPIAuthentication.*)$ replace: '# \1' @@ -111950,36 +127243,100 @@ fi - restrict_strategy - sshd_enable_gssapi_auth +- name: Enable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Enable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + - name: Enable GSSAPI Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter GSSAPIAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ line: GSSAPIAuthentication yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Enable GSSAPI Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity @@ -112007,16 +127364,15 @@ authentication types. To enable PAM authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: UsePAM yes - CCI-000877 - SRG-OS-000125-GPOS-00065 + SRG-OS-000125-GPOS-00065 2.2.6 2.2 - OL09-00-002344 - SV-271707r1091833_rule + OL09-00-002344 + SV-271707r1091833_rule When UsePAM is set to yes, PAM runs through account and session types properly. This is important if you want to restrict access to services based off of IP, time or other factors of the account. Additionally, you can make sure users inherit certain environment variables @@ -112032,21 +127388,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*UsePAM/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112067,7 +127429,7 @@ fi - sshd_enable_pam - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112084,7 +127446,7 @@ fi - sshd_enable_pam - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*UsePAM.*)$ replace: '# \1' @@ -112101,36 +127463,107 @@ fi - restrict_strategy - sshd_enable_pam +- name: Enable PAM - Check if the parameter UsePAM is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Enable PAM - Check if the parameter UsePAM is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + - name: Enable PAM block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePAM\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePAM\s+ + create: false + regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter UsePAM is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*UsePAM\s+ + regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+ line: UsePAM yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Enable PAM - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002344 @@ -112161,25 +127594,23 @@ configuration is used if no value is set for PubkeyAuthentication/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PubkeyAuthentication yes - CCI-000765 - CCI-000766 - SRG-OS-000105-GPOS-00052 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000108-GPOS-00055 - OL09-00-002359 - SV-271721r1091875_rule + SRG-OS-000105-GPOS-00052 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000108-GPOS-00055 + OL09-00-002359 + SV-271721r1091875_rule Without the use of multifactor authentication, the ease of access to privileged functions is greatly increased. Multifactor authentication requires using two or more factors to achieve authentication. A privileged account is defined as an information system account with authorizations of a privileged user. -The DoD CAC with DoD-approved PKI is an example of multifactor -authentication. +Smart cards or hardware tokens paired with digital certificates are +common examples of multifactor implementations. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -112191,21 +127622,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PubkeyAuthentication yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PubkeyAuthentication yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112224,7 +127661,7 @@ fi - sshd_enable_pubkey_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112239,7 +127676,7 @@ fi - sshd_enable_pubkey_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PubkeyAuthentication.*)$ replace: '# \1' @@ -112254,36 +127691,103 @@ fi - restrict_strategy - sshd_enable_pubkey_auth +- name: Enable Public Key Authentication - Check if the parameter PubkeyAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Enable Public Key Authentication - Check if the parameter PubkeyAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + - name: Enable Public Key Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PubkeyAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ line: PubkeyAuthentication yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Enable Public Key Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002359 @@ -112314,7 +127818,7 @@ configuration is used if no value is set for StrictModes. To explicitly enable StrictModes in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: StrictModes yes @@ -112331,7 +127835,6 @@ To explicitly enable StrictModes in SSH, add or correct t DSS05.07 DSS06.02 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -112364,23 +127867,24 @@ To explicitly enable StrictModes in SSH, add or correct t A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 AC-6 AC-17(a) CM-6(a) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002351 - SV-271714r1091854_rule + SRG-OS-000480-GPOS-00227 + 1409 + OL09-00-002351 + SV-271714r1091854_rule If other users have access to modify user-specific SSH configuration files, they may be able to log into the system as another user. # Remediation is applicable only in certain platforms @@ -112394,21 +127898,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*StrictModes/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "StrictModes yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "StrictModes yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112431,7 +127941,7 @@ fi - sshd_enable_strictmodes - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112450,7 +127960,7 @@ fi - sshd_enable_strictmodes - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*StrictModes.*)$ replace: '# \1' @@ -112469,36 +127979,115 @@ fi - restrict_strategy - sshd_enable_strictmodes +- name: Enable Use of Strict Mode Checking - Check if the parameter StrictModes is + configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "StrictModes"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Enable Use of Strict Mode Checking - Check if the parameter StrictModes is + configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "StrictModes"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + - name: Enable Use of Strict Mode Checking block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*StrictModes\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*StrictModes\s+ + create: false + regexp: (?i)(?i)^\s*{{ "StrictModes"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter StrictModes is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "StrictModes"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "StrictModes"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*StrictModes\s+ + regexp: (?i)(?i)^\s*{{ "StrictModes"| regex_escape }}\s+ line: StrictModes yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Enable Use of Strict Mode Checking - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002351 @@ -112527,7 +128116,7 @@ fi across the system, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: Banner /etc/issue Another section contains information on how to create an @@ -112541,12 +128130,6 @@ appropriate system-wide warning banner. DSS05.10 DSS06.10 3.1.9 - CCI-001387 - CCI-001384 - CCI-000048 - CCI-001386 - CCI-001388 - CCI-001385 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -112582,10 +128165,11 @@ appropriate system-wide warning banner. PR.AC-7 FTA_TAB.1 Req-2.2.4 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - OL09-00-000256 - SV-271487r1091173_rule + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + 0484 + OL09-00-000256 + SV-271487r1091173_rule The warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. Alternatively, systems whose ownership should not be obvious should ensure usage of a banner that does @@ -112602,21 +128186,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Banner /etc/issue" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Banner /etc/issue" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112642,7 +128232,7 @@ fi - sshd_enable_warning_banner - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112664,7 +128254,7 @@ fi - sshd_enable_warning_banner - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Banner.*)$ replace: '# \1' @@ -112686,36 +128276,122 @@ fi - restrict_strategy - sshd_enable_warning_banner +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+/etc/issue$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + - name: Enable SSH Warning Banner block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Banner is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Banner\s+ + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ line: Banner /etc/issue state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Enable SSH Warning Banner - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -112756,13 +128432,6 @@ appropriate system-wide warning banner. DSS05.10 DSS06.10 3.1.9 - CCI-000048 - CCI-000050 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -112796,8 +128465,8 @@ appropriate system-wide warning banner. AC-17(a) CM-6(a) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 The warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. Alternatively, systems @@ -112815,21 +128484,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Banner /etc/issue.net" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Banner /etc/issue.net" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112853,7 +128528,7 @@ fi - sshd_enable_warning_banner_net - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112873,7 +128548,7 @@ fi - sshd_enable_warning_banner_net - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Banner.*)$ replace: '# \1' @@ -112893,36 +128568,116 @@ fi - restrict_strategy - sshd_enable_warning_banner_net +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+/etc/issue.net$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + - name: Enable SSH Warning Banner block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Banner is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Banner\s+ + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ line: Banner /etc/issue.net state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Enable SSH Warning Banner - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -112956,7 +128711,7 @@ by users. SSH has the capability to encrypt remote X11 connections when SSH's To enable X11 Forwarding, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: X11Forwarding yes @@ -112980,7 +128735,6 @@ To enable X11 Forwarding, add or correct the following line in BAI10.05 DSS03.01 3.1.13 - CCI-000366 4.3.4.3.2 4.3.4.3.3 4.4.3.3 @@ -112995,14 +128749,14 @@ To enable X11 Forwarding, add or correct the following line in A.14.2.2 A.14.2.3 A.14.2.4 - CIP-007-3 R7.1 + CIP-007-3 R7.1 CM-6(a) AC-17(a) AC-17(2) DE.AE-1 PR.DS-7 PR.IP-1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Non-encrypted X displays allow an attacker to capture keystrokes and to execute commands remotely. # Remediation is applicable only in certain platforms @@ -113016,21 +128770,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "X11Forwarding yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "X11Forwarding yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113052,7 +128812,7 @@ fi - sshd_enable_x11_forwarding - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -113070,7 +128830,7 @@ fi - sshd_enable_x11_forwarding - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*X11Forwarding.*)$ replace: '# \1' @@ -113088,36 +128848,112 @@ fi - restrict_strategy - sshd_enable_x11_forwarding +- name: Enable Encrypted X11 Forwarding - Check if the parameter X11Forwarding is + configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Enable Encrypted X11 Forwarding - Check if the parameter X11Forwarding is + configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + - name: Enable Encrypted X11 Forwarding block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter X11Forwarding is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ line: X11Forwarding yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Enable Encrypted X11 Forwarding - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.13 @@ -113232,16 +129068,16 @@ because each system has unique user names and group names. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-3 CM-6(a) PR.AC-4 @@ -113270,7 +129106,7 @@ The appropriate configuration is used if no value is set for PrintLas To explicitly enable LastLog in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PrintLastLog yes @@ -113281,7 +129117,6 @@ To explicitly enable LastLog in SSH, add or correct the following line in DSS05.04 DSS05.10 DSS06.10 - CCI-000366 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -113307,9 +129142,11 @@ To explicitly enable LastLog in SSH, add or correct the following line in AC-9 AC-9(1) PR.AC-7 - SRG-OS-000480-GPOS-00227 - OL09-00-002352 - SV-271715r1091857_rule + SRG-OS-000480-GPOS-00227 + 0582 + 0846 + OL09-00-002352 + SV-271715r1091857_rule Providing users feedback on when account accesses last occurred facilitates user recognition and reporting of unauthorized account use. # Remediation is applicable only in certain platforms @@ -113323,21 +129160,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PrintLastLog/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PrintLastLog yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PrintLastLog yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113358,7 +129201,7 @@ fi - sshd_print_last_log - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -113375,7 +129218,7 @@ fi - sshd_print_last_log - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PrintLastLog.*)$ replace: '# \1' @@ -113392,36 +129235,108 @@ fi - restrict_strategy - sshd_print_last_log +- name: Enable SSH Print Last Log - Check if the parameter PrintLastLog is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Enable SSH Print Last Log - Check if the parameter PrintLastLog is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + - name: Enable SSH Print Last Log block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PrintLastLog\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PrintLastLog\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PrintLastLog is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*PrintLastLog\s+ + regexp: (?i)(?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ line: PrintLastLog yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Enable SSH Print Last Log - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002352 @@ -113451,20 +129366,17 @@ elapsed. To decrease the default limits, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: RekeyLimit - CCI-002421 - CCI-000068 - CCI-002418 FCS_SSH_EXT.1.8 - SRG-OS-000480-GPOS-00227 - SRG-OS-000033-GPOS-00014 - OL09-00-002342 - SV-271705r1091827_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000033-GPOS-00014 + OL09-00-002342 + SV-271705r1091827_rule By decreasing the limit based on the amount of data and enabling time-based limit, effects of potential attacks against encryption keys are limited. @@ -113476,7 +129388,6 @@ var_rekey_limit_time=' Set LogLevel to INFO - The INFO parameter specifices that record login and logout activity will be logged. + The INFO parameter specifies that record login and logout activity will be logged. The default SSH configuration sets the log level to INFO. The appropriate configuration is used if no value is set for LogLevel. @@ -113765,12 +129826,13 @@ configuration is used if no value is set for LogLevel. To explicitly specify the log level in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: LogLevel INFO AC-17(a) CM-6(a) + 1409 SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically not recommended other than strictly for debugging SSH communications since it provides so much data that it is difficult to identify important security information. INFO level is the @@ -113788,21 +129850,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "LogLevel INFO" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "LogLevel INFO" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113822,7 +129890,7 @@ fi - sshd_set_loglevel_info - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -113838,7 +129906,7 @@ fi - sshd_set_loglevel_info - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*LogLevel.*)$ replace: '# \1' @@ -113854,36 +129922,104 @@ fi - restrict_strategy - sshd_set_loglevel_info +- name: Set LogLevel to INFO - Check if the parameter LogLevel is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Set LogLevel to INFO - Check if the parameter LogLevel is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+INFO$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + - name: Set LogLevel to INFO block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter LogLevel is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ line: LogLevel INFO state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Set LogLevel to INFO - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(a) @@ -113910,21 +130046,20 @@ To specify the log level in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: LogLevel VERBOSE - CCI-000067 - CIP-007-3 R7.1 + CIP-007-3 R7.1 AC-17(a) AC-17(1) CM-6(a) Req-2.2.4 - SRG-OS-000032-GPOS-00013 + SRG-OS-000032-GPOS-00013 2.2.6 2.2 - OL09-00-002340 - SV-271703r1091821_rule + OL09-00-002340 + SV-271703r1091821_rule SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically not recommended other than strictly for debugging SSH communications since it provides so much data that it is difficult to identify important security information. INFO or @@ -113943,21 +130078,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "LogLevel VERBOSE" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "LogLevel VERBOSE" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113982,7 +130123,7 @@ fi - sshd_set_loglevel_verbose - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114003,7 +130144,7 @@ fi - sshd_set_loglevel_verbose - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*LogLevel.*)$ replace: '# \1' @@ -114024,36 +130165,120 @@ fi - restrict_strategy - sshd_set_loglevel_verbose +- name: Set SSH Daemon LogLevel to VERBOSE - Check if the parameter LogLevel is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Set SSH Daemon LogLevel to VERBOSE - Check if the parameter LogLevel is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+VERBOSE$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + - name: Set SSH Daemon LogLevel to VERBOSE block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter LogLevel is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ line: LogLevel VERBOSE state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Set SSH Daemon LogLevel to VERBOSE - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002340 @@ -114088,7 +130313,6 @@ to set MaxAUthTries edit /etc/ssh/sshd_config as follows: 0421 0422 - 0431 0974 1173 1401 @@ -114110,7 +130334,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then sshd_max_auth_tries_value='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114119,21 +130342,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*MaxAuthTries/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114158,7 +130387,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114174,7 +130403,7 @@ fi - sshd_set_max_auth_tries - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*MaxAuthTries.*)$ replace: '# \1' @@ -114190,36 +130419,107 @@ fi - restrict_strategy - sshd_set_max_auth_tries +- name: Set SSH authentication attempt limit - Check if the parameter MaxAuthTries + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + +- name: Set SSH authentication attempt limit - Check if the parameter MaxAuthTries + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+{{ sshd_max_auth_tries_value + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + - name: Set SSH authentication attempt limit block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxAuthTries\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxAuthTries\s+ + create: false + regexp: (?i)(?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter MaxAuthTries is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*MaxAuthTries\s+ + regexp: (?i)(?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ line: MaxAuthTries {{ sshd_max_auth_tries_value }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + +- name: Set SSH authentication attempt limit - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -114258,7 +130558,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_max_sessions='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114267,21 +130566,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*MaxSessions/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114306,7 +130611,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114322,7 +130627,7 @@ fi - sshd_set_max_sessions - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*MaxSessions.*)$ replace: '# \1' @@ -114338,36 +130643,106 @@ fi - restrict_strategy - sshd_set_max_sessions +- name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + +- name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+{{ var_sshd_max_sessions + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + - name: Set SSH MaxSessions limit block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxSessions\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxSessions\s+ + create: false + regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter MaxSessions is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*MaxSessions\s+ + regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ line: MaxSessions {{ var_sshd_max_sessions }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + +- name: Set SSH MaxSessions limit - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -114408,7 +130783,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_set_maxstartups='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114417,21 +130791,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*MaxStartups/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114456,7 +130836,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114472,7 +130852,7 @@ fi - sshd_set_maxstartups - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*MaxStartups.*)$ replace: '# \1' @@ -114488,36 +130868,107 @@ fi - restrict_strategy - sshd_set_maxstartups +- name: Ensure SSH MaxStartups is configured - Check if the parameter MaxStartups + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + +- name: Ensure SSH MaxStartups is configured - Check if the parameter MaxStartups + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxStartups"| regex_escape }}\s+{{ var_sshd_set_maxstartups + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + - name: Ensure SSH MaxStartups is configured block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxStartups\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxStartups\s+ + create: false + regexp: (?i)(?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter MaxStartups is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*MaxStartups\s+ + regexp: (?i)(?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ line: MaxStartups {{ var_sshd_set_maxstartups }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + +- name: Ensure SSH MaxStartups is configured - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -114545,6 +130996,7 @@ Ideally, don't have any active configuration directives in that file, and distri to several files in the /etc/ssh/sshd_config.d directory. 164.312(a) FCS_SSH_EXT.1 + 1409 This form of distributed configuration is considered as a good practice, and as other sshd rules assume that directives in files in the /etc/ssh/sshd_config.d config directory are effective, there has to be a rule that ensures this. Aside from that, having multiple configuration files makes the SSH Server configuration changes easier to partition according to the reason that they were introduced, and therefore it should help to perform merges of hardening updates. # Remediation is applicable only in certain platforms @@ -114600,7 +131052,6 @@ SSH, add or correct the following line in the /etc/ssh/sshd_configDSS05.07 DSS06.02 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -114633,21 +131084,21 @@ SSH, add or correct the following line in the /etc/ssh/sshd_configA.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-17(a) AC-6 PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 SSH daemon privilege separation causes the SSH process to drop root privileges when not needed which would decrease the impact of software vulnerabilities in the unprivileged section. @@ -114657,7 +131108,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_priv_separation='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114666,21 +131116,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114707,7 +131163,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114725,7 +131181,7 @@ fi - sshd_use_priv_separation - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*UsePrivilegeSeparation.*)$ replace: '# \1' @@ -114743,36 +131199,113 @@ fi - restrict_strategy - sshd_use_priv_separation +- name: Enable Use of Privilege Separation - Check if the parameter UsePrivilegeSeparation + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + +- name: Enable Use of Privilege Separation - Check if the parameter UsePrivilegeSeparation + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+{{ var_sshd_priv_separation + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + - name: Enable Use of Privilege Separation block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + create: false + regexp: (?i)(?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter UsePrivilegeSeparation is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + regexp: (?i)(?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ line: UsePrivilegeSeparation {{ var_sshd_priv_separation }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + +- name: Enable Use of Privilege Separation - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.12 @@ -114795,155 +131328,6 @@ fi - - Use Only Strong MACs - Limit the MACs to strong hash algorithms. -The following line in /etc/ssh/sshd_config demonstrates use -of those MACs: -MACs - - - CCI-001453 - AC-17 (2) - SRG-OS-000250-GPOS-00093 - OL09-00-000262 - SV-271490r1092628_rule - MD5 and 96-bit MAC algorithms are considered weak and have been shown to increase -exploitability in SSH downgrade attacks. Weak algorithms continue to have a great deal of -attention as a weak spot that can be exploited with expanded computing power. An -attacker that breaks the algorithm could take advantage of a MiTM position to decrypt the -SSH tunnel and capture credentials and information - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - -sshd_strong_macs='' - - -# Strip any search characters in the key arg so that the key can be replaced without -# adding any search characters to the config file. -stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^MACs") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "$sshd_strong_macs" - -# If the key exists, change it. Otherwise, add it to the config_file. -# We search for the key string followed by a word boundary (matched by \>), -# so if we search for 'setting', 'setting2' won't match. -if LC_ALL=C grep -q -m 1 -i -e "^MACs\\>" "/etc/ssh/sshd_config"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^MACs\\>.*/$escaped_formatted_output/gi" "/etc/ssh/sshd_config" -else - if [[ -s "/etc/ssh/sshd_config" ]] && [[ -n "$(tail -c 1 -- "/etc/ssh/sshd_config" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/ssh/sshd_config" - fi - printf '%s\n' "$formatted_output" >> "/etc/ssh/sshd_config" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs -- name: XCCDF Value sshd_strong_macs # promote to variable - set_fact: - sshd_strong_macs: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*MACs.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs - -- name: Use Only Strong MACs - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MACs\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MACs\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MACs\s+ - line: MACs {{ sshd_strong_macs }} - state: present - insertbefore: BOF - validate: /usr/sbin/sshd -t -f %s - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs - - - - - - - - - - Prevent remote hosts from connecting to the proxy display The SSH daemon should prevent remote hosts from connecting to the proxy @@ -114956,15 +131340,14 @@ To explicitly prevent remote connections to the proxy display, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: X11UseLocalhost yes - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-002354 - SV-271716r1091860_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002354 + SV-271716r1091860_rule When X11 forwarding is enabled, there may be additional exposure to the server and client displays if the sshd proxy display is configured to listen on the wildcard address. By default, sshd binds the forwarding server to the @@ -114982,21 +131365,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*X11UseLocalhost/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "X11UseLocalhost yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "X11UseLocalhost yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -115016,7 +131405,7 @@ fi - sshd_x11_use_localhost - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -115032,7 +131421,7 @@ fi - sshd_x11_use_localhost - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*X11UseLocalhost.*)$ replace: '# \1' @@ -115048,36 +131437,107 @@ fi - restrict_strategy - sshd_x11_use_localhost +- name: Prevent remote hosts from connecting to the proxy display - Check if the parameter + X11UseLocalhost is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Prevent remote hosts from connecting to the proxy display - Check if the parameter + X11UseLocalhost is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + - name: Prevent remote hosts from connecting to the proxy display block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11UseLocalhost\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + create: false + regexp: (?i)(?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter X11UseLocalhost is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + regexp: (?i)(?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ line: X11UseLocalhost yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Prevent remote hosts from connecting to the proxy display - set file mode + for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002354 @@ -115178,7 +131638,10 @@ $ sudo yum install sssd PR.AC-1 PR.AC-6 PR.AC-7 + SRG-OS-000375-GPOS-00160 R67 + OL09-00-000285 + SV-271493r1091191_rule # Remediation is applicable only in certain platforms if rpm --quiet -q sssd-common; then @@ -115195,6 +131658,7 @@ fi package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000285 - NIST-800-53-CM-6(a) - enable_strategy - low_complexity @@ -115204,11 +131668,12 @@ fi - package_sssd_installed - name: Ensure sssd is installed - package: + ansible.builtin.package: name: sssd state: present when: '"sssd-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000285 - NIST-800-53-CM-6(a) - enable_strategy - low_complexity @@ -115298,11 +131763,14 @@ The sssd service can be enabled with the following comman PR.AC-1 PR.AC-6 PR.AC-7 + SRG-OS-000375-GPOS-00160 R67 + OL09-00-000286 + SV-271494r1091194_rule - + # Remediation is applicable only in certain platforms -if rpm --quiet -q sssd-common && { rpm --quiet -q kernel || rpm --quiet -q kernel-uek; }; then +if rpm --quiet -q sssd-common && { ( rpm --quiet -q sssd-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); }; then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'sssd.service' @@ -115319,6 +131787,7 @@ fi package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000286 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(10) - enable_strategy @@ -115332,7 +131801,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the SSSD Service - Enable Service sssd @@ -115343,10 +131812,8 @@ fi masked: false when: - '"sssd-common" in ansible_facts.packages' - when: - - '"sssd-common" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000286 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(10) - enable_strategy @@ -115355,6 +131822,11 @@ fi - medium_severity - no_reboot_needed - service_sssd_enabled + - special_service_block + when: + - '"sssd-common" in ansible_facts.packages' + - ( "sssd-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) include enable_sssd @@ -115369,6 +131841,10 @@ class enable_sssd { [customizations.services] enabled = ["sssd"] + + + + @@ -115383,13 +131859,11 @@ for example, hardware tokens providing time-based or challenge-response authenti Configuring certificate_verification to ocsp_dgst= ensures that certificates for multifactor solutions are checked via Online Certificate Status Protocol (OCSP). - CCI-001954 - CCI-004046 IA-2(11) - SRG-OS-000375-GPOS-00160 - SRG-OS-000377-GPOS-00162 - OL09-00-000930 - SV-271608r1091536_rule + SRG-OS-000375-GPOS-00160 + SRG-OS-000377-GPOS-00162 + OL09-00-000930 + SV-271608r1091536_rule Ensuring that multifactor solutions certificates are checked via Online Certificate Status Protocol (OCSP) ensures the security of the system. # Remediation is applicable only in certain platforms @@ -115415,10 +131889,13 @@ for f in $(echo -n "$MAIN_CONF /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[sssd\]([^\n\[]*\n+)+?[[:space:]]*certificate_verification" "$f"; then + if ! grep -qPz "certificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function" "$f"; then sed -i "s/certificate_verification[^(\n)]*/certificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[sssd\]" "$f"; then @@ -115463,7 +131940,7 @@ fi - always - name: Ensure that "certificate_verification" is not set in /etc/sssd/sssd.conf - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: sssd option: certificate_verification @@ -115481,7 +131958,7 @@ fi - sssd_certificate_verification - name: Ensure that "certificate_verification" is not set in /etc/sssd/conf.d/*.conf - ini_file: + community.general.ini_file: path: /etc/sssd/conf.d/*.conf section: sssd option: certificate_verification @@ -115499,7 +131976,7 @@ fi - sssd_certificate_verification - name: Ensure that "certificate_verification" is set - ini_file: + community.general.ini_file: path: /etc/sssd/conf.d/certificate_verification.conf section: sssd option: certificate_verification @@ -115539,11 +132016,10 @@ domains = testing.test Automatic remediation of this control is not available, since all of the settings in in the certmap need to be customized. - CCI-000187 IA-5 (2) (c) - SRG-OS-000068-GPOS-00036 - OL09-00-000910 - SV-271606r1091530_rule + SRG-OS-000068-GPOS-00036 + OL09-00-000910 + SV-271606r1091530_rule Without mapping the certificate used to authenticate to the user account, the ability to determine the identity of the individual user or group will not be available for forensic analysis. @@ -115575,9 +132051,6 @@ services = sudo, autofs, pam DSS05.10 DSS06.03 DSS06.10 - CCI-004046 - CCI-001953 - CCI-001954 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -115617,9 +132090,9 @@ services = sudo, autofs, pam PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000375-GPOS-00160 - SRG-OS-000376-GPOS-00161 - SRG-OS-000377-GPOS-00162 + SRG-OS-000375-GPOS-00160 + SRG-OS-000376-GPOS-00161 + SRG-OS-000377-GPOS-00162 R67 Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is @@ -115788,7 +132261,7 @@ fi - sssd_enable_pam_services - name: Configure PAM in SSSD Services - Insert entry to /etc/sssd/sssd.conf - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: sssd option: services @@ -115834,12 +132307,14 @@ Also add or update "pam_sss.so" line in auth section of "/etc/pam.d/smartcard-au include the "allow_missing_name" option, like in the following example: /etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name - CCI-000765 - CCI-004047 - CCI-004046 + Req-8.3 + SRG-OS-000375-GPOS-00160 + SRG-OS-000105-GPOS-00052 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000108-GPOS-00055 0421 0422 - 0431 0974 1173 1401 @@ -115851,14 +132326,8 @@ include the "allow_missing_name" option, like in the following example: 1559 1560 1561 - Req-8.3 - SRG-OS-000375-GPOS-00160 - SRG-OS-000105-GPOS-00052 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000108-GPOS-00055 - OL09-00-000925 - SV-271607r1091533_rule + OL09-00-000925 + SV-271607r1091533_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -115867,9 +132336,8 @@ authentication device. Multi-Factor Authentication (MFA) solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q sssd-common; then @@ -115888,10 +132356,13 @@ for f in $(echo -n "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*pam_cert_auth" "$f"; then + if ! grep -qPz "pam_cert_auth=True" "$f"; then sed -i "s/pam_cert_auth[^(\n)]*/pam_cert_auth=True/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[pam\]" "$f"; then @@ -115977,7 +132448,7 @@ fi - sssd_enable_smartcards - name: Test for domain group - command: grep '^\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '^\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -115994,7 +132465,7 @@ fi - sssd_enable_smartcards - name: Add default domain group (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -116023,7 +132494,7 @@ fi - sssd_enable_smartcards - name: Enable Smartcards in SSSD - ini_file: + community.general.ini_file: dest: /etc/sssd/sssd.conf section: pam option: pam_cert_auth @@ -116042,7 +132513,7 @@ fi - sssd_enable_smartcards - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -116097,13 +132568,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Enable Smartcards in SSSD - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - ansible_check_mode or result_authselect_check_cmd.rc == 0 fail_msg: - authselect integrity check failed. Remediation aborted! - This remediation could not be applied because an authselect profile was not @@ -116120,6 +132592,7 @@ fi cmd: authselect current | tail -n+3 | awk '{ print $2 }' register: result_authselect_features changed_when: false + check_mode: false when: - result_authselect_check_cmd is success @@ -116240,6 +132713,7 @@ fi state: present register: result_pam_sssd_enable_smartcards_add when: + - result_pam_module_sssd_enable_smartcards_option_present.found is defined - result_pam_module_sssd_enable_smartcards_option_present.found == 0 - name: Enable Smartcards in SSSD - Define a fact for control already filtered in @@ -116328,6 +132802,7 @@ fi state: present register: result_pam_sssd_enable_smartcards_add when: + - result_pam_module_sssd_enable_smartcards_option_present.found is defined - result_pam_module_sssd_enable_smartcards_option_present.found == 0 when: - '"sssd-common" in ansible_facts.packages' @@ -116353,13 +132828,11 @@ fi SSSD Has a Correct Trust Anchor SSSD must have acceptable trust anchor present. Automatic remediation of this control is not available. - CCI-004068 - CCI-000185 IA-5 (2) (a) - SRG-OS-000066-GPOS-00034 - SRG-OS-000384-GPOS-00167 - OL09-00-000900 - SV-271604r1091524_rule + SRG-OS-000066-GPOS-00034 + SRG-OS-000384-GPOS-00167 + OL09-00-000900 + SV-271604r1091524_rule Without path validation, an informed trust decision by the relying party cannot be made when presented with any certificate not already explicitly trusted. @@ -116410,7 +132883,6 @@ offline_credentials_expiration = 1 DSS05.10 DSS06.03 DSS06.10 - CCI-002007 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -116450,9 +132922,9 @@ offline_credentials_expiration = 1 PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000383-GPOS-00166 - OL09-00-000935 - SV-271609r1091539_rule + SRG-OS-000383-GPOS-00166 + OL09-00-000935 + SV-271609r1091539_rule If cached authentication information is out-of-date, the validity of the authentication information may be questionable. # Remediation is applicable only in certain platforms @@ -116473,10 +132945,13 @@ for f in $(echo -n "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*offline_credentials_expiration" "$f"; then + if ! grep -qPz "offline_credentials_expiration=1" "$f"; then sed -i "s/offline_credentials_expiration[^(\n)]*/offline_credentials_expiration=1/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[pam\]" "$f"; then @@ -116517,7 +132992,7 @@ fi - sssd_offline_cred_expiration - name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -116535,7 +133010,7 @@ fi - sssd_offline_cred_expiration - name: Add default domain group (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -116565,7 +133040,7 @@ fi - sssd_offline_cred_expiration - name: Configure SSD to Expire Offline Credentials - ini_file: + community.general.ini_file: dest: /etc/sssd/sssd.conf section: pam option: offline_credentials_expiration @@ -116585,7 +133060,7 @@ fi - sssd_offline_cred_expiration - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -116644,10 +133119,9 @@ allows SSSD to fetch identity information from an LDAP server.ldap_tls_reqcert option in /etc/sssd/sssd.conf to demand. - CCI-001453 SC-12(3) CM-6(a) - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 R67 Without a valid certificate presented to the LDAP client backend, the identity of a server can be forged compromising LDAP remote access sessions. @@ -116702,7 +133176,7 @@ fi - unknown_strategy - name: Test for id_provider different than Active Directory (ad) - command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' + ansible.builtin.command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' /etc/sssd/sssd.conf register: test_id_provider failed_when: false @@ -116722,7 +133196,7 @@ fi - unknown_strategy - name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -116742,7 +133216,7 @@ fi - name: Add default domain group and set ldap_tls_reqcert in sssd configuration (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -116773,7 +133247,7 @@ fi - unknown_strategy - name: Set ldap_tls_reqcert in sssd configuration - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ test_grep_domain.stdout | regex_replace(''\[(.*)\]'',''\1'') }}' option: ldap_tls_reqcert @@ -116797,7 +133271,7 @@ fi - unknown_strategy - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -116870,7 +133344,6 @@ set to ldap or ipa, use the follow DSS05.03 DSS05.05 DSS06.06 - CCI-001453 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -116944,7 +133417,7 @@ set to ldap or ipa, use the follow PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 R67 Without cryptographic integrity protections, information can be altered by unauthorized users without detection. The ssl directive specifies @@ -117002,7 +133475,7 @@ fi - unknown_strategy - name: Test for id_provider different than Active Directory (ad) - command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' + ansible.builtin.command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' /etc/sssd/sssd.conf register: test_id_provider failed_when: false @@ -117023,7 +133496,7 @@ fi - unknown_strategy - name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -117044,7 +133517,7 @@ fi - name: Add default domain group and set ldap_id_use_start_tls in sssd configuration (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -117076,7 +133549,7 @@ fi - unknown_strategy - name: Set ldap_id_use_start_tls in sssd configuration - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ test_grep_domain.stdout | regex_replace(''\[(.*)\]'',''\1'') }}' option: ldap_id_use_start_tls @@ -117101,7 +133574,7 @@ fi - unknown_strategy - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -117159,17 +133632,15 @@ The usbguard package can be installed with the following $ sudo yum install usbguard - CCI-001958 - CCI-003959 - 1418 CM-8(3) IA-3 FMT_SMF_EXT.1 - SRG-OS-000378-GPOS-00163 - SRG-APP-000141-CTR-000315 + SRG-OS-000378-GPOS-00163 + SRG-APP-000141-CTR-000315 A.23.SEC-OL1 - OL09-00-000320 - SV-271503r1091221_rule + 1418 + OL09-00-000320 + SV-271503r1091221_rule usbguard is a software framework that helps to protect against rogue USB devices by implementing basic whitelisting/blacklisting capabilities based on USB device attributes. @@ -117199,7 +133670,7 @@ fi - package_usbguard_installed - name: Ensure usbguard is installed - package: + ansible.builtin.package: name: usbguard state: present when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages @@ -117255,17 +133726,15 @@ version = "*" The usbguard service can be enabled with the following command: $ sudo systemctl enable usbguard.service - CCI-001958 - CCI-003959 - 1418 CM-8(3)(a) IA-3 FMT_SMF_EXT.1 - SRG-OS-000378-GPOS-00163 - SRG-APP-000141-CTR-000315 + SRG-OS-000378-GPOS-00163 + SRG-APP-000141-CTR-000315 A.23.SEC-OL1 - OL09-00-000321 - SV-271504r1091224_rule + 1418 + OL09-00-000321 + SV-271504r1091224_rule The usbguard service must be running in order to enforce the USB device authorization policy for all USB devices. # Remediation is applicable only in certain platforms @@ -117300,7 +133769,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the USBGuard Service - Enable Service usbguard @@ -117311,8 +133780,6 @@ fi masked: false when: - '"usbguard" in ansible_facts.packages' - when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-000321 - NIST-800-53-CM-8(3)(a) @@ -117323,6 +133790,9 @@ fi - medium_severity - no_reboot_needed - service_usbguard_enabled + - special_service_block + when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) include enable_usbguard @@ -117352,6 +133822,10 @@ spec: [customizations.services] enabled = ["usbguard"] + + + + @@ -117365,25 +133839,24 @@ enabled = ["usbguard"] (as opposed directly to a file), AuditBackend option in /etc/usbguard/usbguard-daemon.conf needs to be set to LinuxAudit. - CCI-000169 AU-2 CM-8(3) IA-3 FMT_SMF_EXT.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000471-GPOS-00215 - SRG-APP-000141-CTR-000315 - OL09-00-002330 - SV-271700r1091812_rule + SRG-OS-000062-GPOS-00031 + SRG-OS-000471-GPOS-00215 + SRG-APP-000141-CTR-000315 + OL09-00-002330 + SV-271700r1091812_rule Using the Linux Audit logging allows for centralized trace of events. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { rpm --quiet -q usbguard; }; then if [ -e "/etc/usbguard/usbguard-daemon.conf" ] ; then - LC_ALL=C sed -i "/^\s*AuditBackend=/d" "/etc/usbguard/usbguard-daemon.conf" + LC_ALL=C sed -i "/^[ \\t]*AuditBackend=/Id" "/etc/usbguard/usbguard-daemon.conf" else touch "/etc/usbguard/usbguard-daemon.conf" fi @@ -117400,7 +133873,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -117408,39 +133881,39 @@ fi - NIST-800-53-AU-2 - NIST-800-53-CM-8(3) - NIST-800-53-IA-3 + - configure_strategy - configure_usbguard_auditbackend - low_complexity - low_disruption - low_severity - no_reboot_needed - - restrict_strategy - name: Log USBGuard daemon audit events using Linux Audit block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/usbguard-daemon.conf create: true - regexp: (?i)^\s*AuditBackend= + regexp: (?i)^[ \\t]*AuditBackend= state: absent check_mode: true changed_when: false register: dupes - name: Deduplicate values from /etc/usbguard/usbguard-daemon.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/usbguard-daemon.conf create: true - regexp: (?i)^\s*AuditBackend= + regexp: (?i)^[ \\t]*AuditBackend= state: absent when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/usbguard/usbguard-daemon.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/usbguard-daemon.conf create: true - regexp: (?i)^\s*AuditBackend= + regexp: (?i)^[ \\t]*AuditBackend= line: AuditBackend=LinuxAudit state: present when: @@ -117452,12 +133925,12 @@ fi - NIST-800-53-AU-2 - NIST-800-53-CM-8(3) - NIST-800-53-IA-3 + - configure_strategy - configure_usbguard_auditbackend - low_complexity - low_disruption - low_severity - no_reboot_needed - - restrict_strategy --- apiVersion: machineconfiguration.openshift.io/v1 @@ -117496,8 +133969,9 @@ to /etc/usbguard/rules.conf. CM-8(3) IA-3 FMT_SMF_EXT.1 - SRG-OS-000114-GPOS-00059 - SRG-APP-000092-CTR-000165 + SRG-OS-000114-GPOS-00059 + SRG-APP-000092-CTR-000165 + 1418 Without allowing Human Interface Devices, it might not be possible to interact with the system. Without allowing hubs, it might not be possible to use any USB devices on the system. @@ -117524,7 +133998,7 @@ fi - usbguard_allow_hid_and_hub - name: Allow HID devices and hubs - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/rules.conf create: true regexp: '' @@ -117573,13 +134047,12 @@ spec: to inaccessible system if they use USB mouse/keyboard. To prevent this scenario, the initial policy configuration must be generated based on current connected USB devices. - CCI-001958 CM-8(3)(a) IA-3 - SRG-OS-000378-GPOS-00163 + SRG-OS-000378-GPOS-00163 A.23.SEC-OL1 - OL09-00-002331 - SV-271701r1091815_rule + OL09-00-002331 + SV-271701r1091815_rule The usbguard must be configured to allow connected USB devices to work properly, avoiding the system to become inaccessible. # Remediation is applicable only in certain platforms @@ -117630,35 +134103,35 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Check that the /etc/usbguard/rules.conf exists - stat: + ansible.builtin.stat: path: /etc/usbguard/rules.conf register: policy_file - name: Create USBGuard Policy configuration - command: usbguard generate-policy + ansible.builtin.command: usbguard generate-policy register: policy when: not policy_file.stat.exists or policy_file.stat.size == 0 - name: Copy the Generated Policy configuration to a persistent file - copy: + ansible.builtin.copy: content: '{{ policy.stdout }}' dest: /etc/usbguard/rules.conf mode: 384 when: not policy_file.stat.exists or policy_file.stat.size == 0 - name: Add comment into /etc/usbguard/rules.conf when system has no USB devices - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/rules.conf line: '# No USB devices found' state: present when: not policy_file.stat.exists or policy_file.stat.size == 0 - name: Enable service usbguard - systemd: + ansible.builtin.systemd: name: usbguard enabled: 'yes' state: started @@ -117719,7 +134192,6 @@ continuing installation. DSS01.04 DSS05.02 DSS05.03 - CCI-000366 4.3.3.6.6 SR 1.13 SR 2.6 @@ -117744,22 +134216,23 @@ continuing installation. CM-6(a) PR.AC-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security vulnerabilities and should not be installed unless approved and documented. # CAUTION: This remediation script will remove xorg-x11-server-common -# from the system, and may remove any packages -# that depend on xorg-x11-server-common. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on xorg-x11-server-common. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "xorg-x11-server-common" ; then yum remove -y "xorg-x11-server-common" fi - - name: Ensure xorg-x11-server-common is removed - package: + - name: 'Remove the X Windows Package Group: Ensure xorg-x11-server-common is removed' + ansible.builtin.package: name: xorg-x11-server-common state: absent tags: @@ -117773,7 +134246,8 @@ fi - no_reboot_needed - package_xorg-x11-server-common_removed - include remove_xorg-x11-server-common + +include remove_xorg-x11-server-common class remove_xorg-x11-server-common { package { 'xorg-x11-server-common': @@ -117782,6 +134256,7 @@ class remove_xorg-x11-server-common { } + package --remove=xorg-x11-server-common @@ -117793,14 +134268,15 @@ package --remove=xorg-x11-server-common Disable graphical user interface - By removing the following packages, the system no longer has X Windows installed. - -xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland + By removing the following packages, the system no longer has X Windows installed. + xorg-x11-server-Xorg + xorg-x11-server-common + xorg-x11-server-utils + xorg-x11-server-Xwayland If X Windows is not installed then the system cannot boot into graphical user mode. This prevents the system from being accidentally or maliciously booted into a graphical.target mode. To do so, run the following command: - sudo yum remove xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your @@ -117810,37 +134286,76 @@ again. The rule xwindows_runlevel_target can be used to configure the system to boot into the multi-user.target. If a GUI is an operational requirement, a tailored profile that removes this rule should be used before continuing installation. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-000145 - SV-271465r1091107_rule - Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security -vulnerabilities and should not be installed unless approved and documented. + SRG-OS-000480-GPOS-00227 + OL09-00-000145 + SV-271465r1091107_rule + Unnecessary service packages must not be installed to decrease the attack surface of the system. +X windows has a long history of security vulnerabilities and should not be installed unless approved and documented. - # remove packages + if rpm -q --quiet "xorg-x11-server-Xorg" ; then yum remove -y "xorg-x11-server-Xorg" fi -if rpm -q --quiet "xorg-x11-server-utils" ; then -yum remove -y "xorg-x11-server-utils" -fi + if rpm -q --quiet "xorg-x11-server-common" ; then yum remove -y "xorg-x11-server-common" fi +if rpm -q --quiet "xorg-x11-server-utils" ; then +yum remove -y "xorg-x11-server-utils" +fi + if rpm -q --quiet "xorg-x11-server-Xwayland" ; then yum remove -y "xorg-x11-server-Xwayland" fi - - name: Ensure xorg packages are removed - package: - name: - - xorg-x11-server-Xorg - - xorg-x11-server-common - - xorg-x11-server-utils - - xorg-x11-server-Xwayland + - name: Disable graphical user interface - Ensure xorg-x11-server-Xorg is removed + ansible.builtin.package: + name: xorg-x11-server-Xorg + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + +- name: Disable graphical user interface - Ensure xorg-x11-server-common is removed + ansible.builtin.package: + name: xorg-x11-server-common + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + +- name: Disable graphical user interface - Ensure xorg-x11-server-utils is removed + ansible.builtin.package: + name: xorg-x11-server-utils + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + +- name: Disable graphical user interface - Ensure xorg-x11-server-Xwayland is removed + ansible.builtin.package: + name: xorg-x11-server-Xwayland state: absent tags: - DISA-STIG-OL09-00-000145 @@ -117853,7 +134368,15 @@ fi - xwindows_remove_packages -package --remove=xorg-x11-server-Xorg --remove=xorg-x11-server-common --remove=xorg-x11-server-utils --remove=xorg-x11-server-Xwayland +# remove packages + +package --remove=xorg-x11-server-Xorg + +package --remove=xorg-x11-server-common + +package --remove=xorg-x11-server-utils + +package --remove=xorg-x11-server-Xwayland @@ -117881,7 +134404,6 @@ Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/syst DSS01.04 DSS05.02 DSS05.03 - CCI-000366 4.3.3.6.6 SR 1.13 SR 2.6 @@ -117906,9 +134428,9 @@ Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/syst CM-6(a) PR.AC-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-000020 - SV-271440r1092462_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000020 + SV-271440r1092462_rule Services that are not required for system and application processes must not be active to decrease the attack surface of the system. @@ -117937,7 +134459,7 @@ fi - xwindows_runlevel_target - name: Switch to multi-user runlevel - file: + ansible.builtin.file: src: /usr/lib/systemd/system/multi-user.target dest: /etc/systemd/system/default.target state: link @@ -118050,18 +134572,25 @@ the process, which in this case, is exe="/usr/sbin/httpd" + + Audit backlog limit + Value of the audit_backlog_limit argument in GRUB 2 configuration. +The audit_backlog_limit parameter determines how auditd records can +be held in the auditd backlog. + 8192 + 8192 + Install audispd-plugins Package The audispd-plugins package can be installed with the following command: $ sudo yum install audispd-plugins - CCI-001851 - SRG-OS-000342-GPOS-00133 + SRG-OS-000342-GPOS-00133 10.3.3 10.3 - OL09-00-000450 - SV-271521r1091275_rule + OL09-00-000450 + SV-271521r1091275_rule audispd-plugins provides plugins for the real-time interface to the audit subsystem, audispd. These plugins can do things like relay events to remote machines or analyze events for suspicious behavior. @@ -118091,7 +134620,7 @@ fi - package_audispd-plugins_installed - name: Ensure audispd-plugins is installed - package: + ansible.builtin.package: name: audispd-plugins state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -118132,38 +134661,13 @@ version = "*" Ensure the audit Subsystem is Installed The audit package should be installed. - CCI-000133 - CCI-001881 - CCI-001875 - CCI-000154 - CCI-001882 - CCI-000158 - CCI-001914 - CCI-000169 - CCI-001464 - CCI-001878 - CCI-001877 - CCI-001889 - CCI-000135 - CCI-002884 - CCI-001487 - CCI-003938 - CCI-000132 - CCI-000134 - CCI-000172 - CCI-000130 - CCI-000131 - CCI-001879 - CCI-001880 - CCI-001876 - CCI-000159 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(C) 164.310(a)(2)(iv) 164.310(d)(2)(iii) 164.312(b) - CIP-004-6 R3.3 - CIP-007-3 R6.5 + CIP-004-6 R3.3 + CIP-007-3 R6.5 AC-7(a) AU-7(1) AU-7(2) @@ -118173,36 +134677,38 @@ version = "*" CM-6(a) FAU_GEN.1 Req-10.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000037-GPOS-00015 - SRG-OS-000038-GPOS-00016 - SRG-OS-000039-GPOS-00017 - SRG-OS-000040-GPOS-00018 - SRG-OS-000041-GPOS-00019 - SRG-OS-000042-GPOS-00021 - SRG-OS-000051-GPOS-00024 - SRG-OS-000054-GPOS-00025 - SRG-OS-000122-GPOS-00063 - SRG-OS-000254-GPOS-00095 - SRG-OS-000255-GPOS-00096 - SRG-OS-000337-GPOS-00129 - SRG-OS-000348-GPOS-00136 - SRG-OS-000349-GPOS-00137 - SRG-OS-000350-GPOS-00138 - SRG-OS-000351-GPOS-00139 - SRG-OS-000352-GPOS-00140 - SRG-OS-000353-GPOS-00141 - SRG-OS-000354-GPOS-00142 - SRG-OS-000358-GPOS-00145 - SRG-OS-000365-GPOS-00152 - SRG-OS-000392-GPOS-00172 - SRG-OS-000475-GPOS-00220 + SRG-OS-000062-GPOS-00031 + SRG-OS-000037-GPOS-00015 + SRG-OS-000038-GPOS-00016 + SRG-OS-000039-GPOS-00017 + SRG-OS-000040-GPOS-00018 + SRG-OS-000041-GPOS-00019 + SRG-OS-000042-GPOS-00021 + SRG-OS-000051-GPOS-00024 + SRG-OS-000054-GPOS-00025 + SRG-OS-000122-GPOS-00063 + SRG-OS-000254-GPOS-00095 + SRG-OS-000255-GPOS-00096 + SRG-OS-000337-GPOS-00129 + SRG-OS-000348-GPOS-00136 + SRG-OS-000349-GPOS-00137 + SRG-OS-000350-GPOS-00138 + SRG-OS-000351-GPOS-00139 + SRG-OS-000352-GPOS-00140 + SRG-OS-000353-GPOS-00141 + SRG-OS-000354-GPOS-00142 + SRG-OS-000358-GPOS-00145 + SRG-OS-000365-GPOS-00152 + SRG-OS-000392-GPOS-00172 + SRG-OS-000475-GPOS-00220 R33 R73 + 0582 + 0846 10.2.1 10.2 - OL09-00-000440 - SV-271519r1091269_rule + OL09-00-000440 + SV-271519r1091269_rule The auditd service is an access monitoring and accounting daemon, watching system calls to audit any access, in comparison with potential local access control policy such as SELinux policy. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -118238,7 +134744,7 @@ fi - package_audit_installed - name: Ensure audit is installed - package: + ansible.builtin.package: name: audit state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -118340,31 +134846,6 @@ The auditd service can be enabled with the following comm 3.3.1 3.3.2 3.3.6 - CCI-000133 - CCI-001881 - CCI-001875 - CCI-000154 - CCI-001882 - CCI-000158 - CCI-001914 - CCI-000169 - CCI-001464 - CCI-001878 - CCI-001877 - CCI-001889 - CCI-000135 - CCI-002884 - CCI-001487 - CCI-003938 - CCI-000132 - CCI-004188 - CCI-000134 - CCI-000172 - CCI-000130 - CCI-000131 - CCI-001879 - CCI-001880 - CCI-001876 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(C) 164.310(a)(2)(iv) @@ -118418,8 +134899,8 @@ The auditd service can be enabled with the following comm A.16.1.7 A.6.2.1 A.6.2.2 - CIP-004-6 R3.3 - CIP-007-3 R6.5 + CIP-004-6 R3.3 + CIP-007-3 R6.5 AC-2(g) AU-3 AU-10 @@ -118442,40 +134923,41 @@ The auditd service can be enabled with the following comm RS.AN-4 FAU_GEN.1 Req-10.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000037-GPOS-00015 - SRG-OS-000038-GPOS-00016 - SRG-OS-000039-GPOS-00017 - SRG-OS-000040-GPOS-00018 - SRG-OS-000041-GPOS-00019 - SRG-OS-000042-GPOS-00021 - SRG-OS-000051-GPOS-00024 - SRG-OS-000054-GPOS-00025 - SRG-OS-000122-GPOS-00063 - SRG-OS-000254-GPOS-00095 - SRG-OS-000255-GPOS-00096 - SRG-OS-000337-GPOS-00129 - SRG-OS-000348-GPOS-00136 - SRG-OS-000349-GPOS-00137 - SRG-OS-000350-GPOS-00138 - SRG-OS-000351-GPOS-00139 - SRG-OS-000352-GPOS-00140 - SRG-OS-000353-GPOS-00141 - SRG-OS-000354-GPOS-00142 - SRG-OS-000358-GPOS-00145 - SRG-OS-000365-GPOS-00152 - SRG-OS-000392-GPOS-00172 - SRG-OS-000475-GPOS-00220 - SRG-APP-000095-CTR-000170 - SRG-APP-000409-CTR-000990 - SRG-APP-000508-CTR-001300 - SRG-APP-000510-CTR-001310 + SRG-OS-000062-GPOS-00031 + SRG-OS-000037-GPOS-00015 + SRG-OS-000038-GPOS-00016 + SRG-OS-000039-GPOS-00017 + SRG-OS-000040-GPOS-00018 + SRG-OS-000041-GPOS-00019 + SRG-OS-000042-GPOS-00021 + SRG-OS-000051-GPOS-00024 + SRG-OS-000054-GPOS-00025 + SRG-OS-000122-GPOS-00063 + SRG-OS-000254-GPOS-00095 + SRG-OS-000255-GPOS-00096 + SRG-OS-000337-GPOS-00129 + SRG-OS-000348-GPOS-00136 + SRG-OS-000349-GPOS-00137 + SRG-OS-000350-GPOS-00138 + SRG-OS-000351-GPOS-00139 + SRG-OS-000352-GPOS-00140 + SRG-OS-000353-GPOS-00141 + SRG-OS-000354-GPOS-00142 + SRG-OS-000358-GPOS-00145 + SRG-OS-000365-GPOS-00152 + SRG-OS-000392-GPOS-00172 + SRG-OS-000475-GPOS-00220 + SRG-APP-000095-CTR-000170 + SRG-APP-000409-CTR-000990 + SRG-APP-000508-CTR-001300 + SRG-APP-000510-CTR-001310 R33 R73 + 1409 10.2.1 10.2 - OL09-00-000441 - SV-271520r1091272_rule + OL09-00-000441 + SV-271520r1091272_rule Without establishing what type of events occurred, it would be difficult to establish, correlate, and investigate the events leading up to an outage or attack. Ensuring the auditd service is active ensures audit records @@ -118533,7 +135015,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable auditd Service - Enable Service auditd @@ -118544,9 +135026,6 @@ fi masked: false when: - '"audit" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - '"audit" in ansible_facts.packages' tags: - CJIS-5.4.1.1 - DISA-STIG-OL09-00-000441 @@ -118571,6 +135050,10 @@ fi - medium_severity - no_reboot_needed - service_auditd_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"audit" in ansible_facts.packages' include enable_auditd @@ -118597,6 +135080,10 @@ spec: [customizations.services] enabled = ["auditd"] + + + + @@ -118656,12 +135143,6 @@ Run the following command to update command line for already installed kernels:< MEA01.05 MEA02.01 3.3.1 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-001464 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(C) 164.310(a)(2)(iv) @@ -118728,18 +135209,18 @@ Run the following command to update command line for already installed kernels:< RS.AN-4 FAU_GEN.1 Req-10.3 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000473-GPOS-00218 - SRG-OS-000254-GPOS-00095 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000473-GPOS-00218 + SRG-OS-000254-GPOS-00095 10.7.2 10.7 - OL09-00-000750 - SV-271577r1091443_rule + OL09-00-000750 + SV-271577r1091443_rule Each process on the system carries an "auditable" flag which indicates whether its activities can be audited. Although auditd takes care of enabling this for all processes which launch after it does, adding the kernel argument @@ -118748,15 +135229,12 @@ ensures it is set for every process during boot. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "audit" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit=[^\"]*\"(.*]\s*)/\1\"audit=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit=[^\"]*\"(.*]\s*)/\1\"audit=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"audit=$expected_value\"]" >> "$KARGS_DIR/10-audit.toml" + echo "kargs = [\"audit=1\"]" >> "$KARGS_DIR/10-audit.toml" fi else @@ -118790,8 +135268,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="audit=1" +- name: Check if audit argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -118813,6 +135293,60 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if audit argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000750 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-17(1) + - NIST-800-53-AU-10 + - NIST-800-53-AU-14(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-IR-5(1) + - PCI-DSS-Req-10.3 + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 + - grub2_audit_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="audit=1" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('audit=1')) or ((etc_default_grub['content'] + | b64decode) is not search('audit=1')) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000750 + - NIST-800-171-3.3.1 + - NIST-800-53-AC-17(1) + - NIST-800-53-AU-10 + - NIST-800-53-AU-14(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-IR-5(1) + - PCI-DSS-Req-10.3 + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 + - grub2_audit_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "audit=1" @@ -118827,32 +135361,33 @@ append = "audit=1" Extend Audit Backlog Limit for the Audit Daemon To improve the kernel capacity to queue all log events, even those which occurred -prior to the audit daemon, add the argument audit_backlog_limit=8192 to the default +prior to the audit daemon, add the argument audit_backlog_limit= + to the default GRUB 2 command line for the Linux operating system. -To ensure that audit_backlog_limit=8192 is added as a kernel command line -argument to newly installed kernels, add audit_backlog_limit=8192 to the +To ensure that audit_backlog_limit= + is added as a kernel command line +argument to newly installed kernels, add audit_backlog_limit= + to the default Grub2 command line for Linux operating systems. Modify the line within /etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... audit_backlog_limit=8192 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit_backlog_limit=8192" +GRUB_CMDLINE_LINUX="... audit_backlog_limit= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit_backlog_limit=" - CCI-001849 - CCI-001464 CM-6(a) FAU_STG.1 FAU_STG.3 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000254-GPOS-00095 - SRG-OS-000341-GPOS-00132 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000254-GPOS-00095 + SRG-OS-000341-GPOS-00132 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 10.7.2 10.7 - OL09-00-000830 - SV-271592r1091488_rule + OL09-00-000830 + SV-271592r1091488_rule audit_backlog_limit sets the queue length for audit events awaiting transfer to the audit daemon. Until the audit daemon is up and running, all log messages are stored in this queue. If the queue is overrun during boot process, the action @@ -118861,19 +135396,20 @@ defined by audit failure flag is taken. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -expected_value="8192" +var_audit_backlog_limit='' -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then + +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then KARGS_DIR="/usr/lib/bootc/kargs.d/" if grep -q -E "audit_backlog_limit" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit_backlog_limit=[^\"]*\"(.*]\s*)/\1\"audit_backlog_limit=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit_backlog_limit=[^\"]*\"(.*]\s*)/\1\"audit_backlog_limit=$var_audit_backlog_limit\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"audit_backlog_limit=$expected_value\"]" >> "$KARGS_DIR/10-audit_backlog_limit.toml" + echo "kargs = [\"audit_backlog_limit=$var_audit_backlog_limit\"]" >> "$KARGS_DIR/10-audit_backlog_limit.toml" fi else - grubby --update-kernel=ALL --args=audit_backlog_limit=8192 + grubby --update-kernel=ALL --args=audit_backlog_limit=$var_audit_backlog_limit fi @@ -118895,9 +135431,16 @@ fi - medium_complexity - reboot_required - restrict_strategy +- name: XCCDF Value var_audit_backlog_limit # promote to variable + set_fact: + var_audit_backlog_limit: !!str + tags: + - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="audit_backlog_limit=8192" +- name: Check if audit_backlog_limit argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -118912,11 +135455,54 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if audit_backlog_limit argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000830 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 + - grub2_audit_backlog_limit_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="audit_backlog_limit={{ + var_audit_backlog_limit }}" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('audit_backlog_limit=' ~ var_audit_backlog_limit)) + or ((etc_default_grub['content'] | b64decode) is not search('audit_backlog_limit=' + ~ var_audit_backlog_limit)) + tags: + - DISA-STIG-OL09-00-000830 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 + - grub2_audit_backlog_limit_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] -append = "audit_backlog_limit=8192" +append = "audit_backlog_limit=" + @@ -118974,6 +135560,359 @@ If the value is set to "1", the system is configured to only send information to 1 2 + + Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ + At a minimum, the audit system should collect administrator actions +for all users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/cron.d/ -p wa -k cronjobs + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/cron.d/ -p wa -k cronjobs + + SRG-OS-000471-GPOS-00215 + OL09-00-002584 + SV-278952r1135407_rule + The actions taken by system administrators should be audited to keep a record +of what was executed on the system, as well as, for accountability purposes. +Editing the sudoers file may be sign of an attacker trying to +establish persistent methods to a system, auditing the editing of the sudoers +files mitigates this risk. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/cron.d/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/cron.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/cron.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/cron.d/ -p wa -k actions" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/cron.d/" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/actions.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/actions.rules" + # If the actions.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/cron.d/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/cron.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/cron.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/cron.d/ -p wa -k actions" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Check if watch + rule for /etc/cron.d/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/etc/cron.d/\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Search /etc/audit/rules.d + for other rules with specified key actions + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)actions$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/actions.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Add watch rule + for /etc/cron.d/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /etc/cron.d/ -p wa -k actions + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Check if watch + rule for /etc/cron.d/ already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/etc/cron.d/\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Add watch rule + for /etc/cron.d/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /etc/cron.d/ -p wa -k actions + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + Make the auditd Configuration Immutable If the auditd daemon is configured to use the @@ -119028,9 +135967,6 @@ With this setting, a reboot will be required to change any audit rules.MEA02.01 3.3.1 3.4.3 - CCI-000163 - CCI-000164 - CCI-000162 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -119104,16 +136040,16 @@ With this setting, a reboot will be required to change any audit rules.RS.AN-1 RS.AN-4 Req-10.5.2 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000119-CTR-000245 - SRG-APP-000120-CTR-000250 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000119-CTR-000245 + SRG-APP-000120-CTR-000250 R73 10.3.2 10.3 - OL09-00-008005 - SV-271886r1092370_rule + OL09-00-008005 + SV-271886r1092370_rule Making the audit configuration immutable prevents accidental as well as malicious modification of the audit rules, although it may be problematic if legitimate changes are needed during system @@ -119169,8 +136105,9 @@ fi - reboot_required - restrict_strategy -- name: Collect all files from /etc/audit/rules.d with .rules extension - find: +- name: Make the auditd Configuration Immutable - Collect all files from /etc/audit/rules.d + with .rules extension + ansible.builtin.find: paths: /etc/audit/rules.d/ patterns: '*.rules' register: find_rules_d @@ -119194,13 +136131,14 @@ fi - reboot_required - restrict_strategy -- name: Remove the -e option from all Audit config files - lineinfile: +- name: Make the auditd Configuration Immutable - Check if target files exist and + get their content + ansible.builtin.stat: path: '{{ item }}' - regexp: ^\s*(?:-e)\s+.*$ - state: absent - loop: '{{ find_rules_d.files | map(attribute=''path'') | list + [''/etc/audit/audit.rules''] - }}' + register: audit_files_stat + loop: + - /etc/audit/audit.rules + - /etc/audit/rules.d/immutable.rules when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -119221,11 +136159,130 @@ fi - reboot_required - restrict_strategy -- name: Add Audit -e option into /etc/audit/rules.d/immutable.rules and /etc/audit/audit.rules - lineinfile: +- name: Make the auditd Configuration Immutable - Read content of existing audit files + ansible.builtin.slurp: + src: '{{ item.item }}' + register: audit_files_content + loop: '{{ audit_files_stat.results }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.stat.exists + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Check if -e 2 is already correctly + set in target files + ansible.builtin.set_fact: + immutable_correctly_set: |- + {{ + audit_files_content.results + | selectattr('content', 'defined') + | map(attribute='content') + | map('b64decode') + | select('search', '^-e 2$', multiline=True) + | list + | length == 2 + }} + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Remove any existing -e option from + all Audit config files + ansible.builtin.lineinfile: + path: '{{ item }}' + regexp: ^\s*-e\s+.*$ + state: absent + loop: '{{ find_rules_d.files | map(attribute=''path'') | list + [''/etc/audit/audit.rules''] + }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not immutable_correctly_set + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Ensure target directories exist + ansible.builtin.file: + path: '{{ item | dirname }}' + state: directory + mode: '0750' + loop: + - /etc/audit/audit.rules + - /etc/audit/rules.d/immutable.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not immutable_correctly_set + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Add Audit -e 2 option to make rules + immutable + ansible.builtin.lineinfile: path: '{{ item }}' create: true line: -e 2 + regexp: ^\s*-e\s+.*$ mode: g-rwx,o-rwx loop: - /etc/audit/audit.rules @@ -119233,6 +136290,7 @@ fi when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not immutable_correctly_set tags: - CJIS-5.4.1.1 - DISA-STIG-OL09-00-008005 @@ -119274,17 +136332,13 @@ utility to read audit rules during daemon startup, add the following line to immutable: --loginuid-immutable - CCI-000163 - CCI-000172 - CCI-000164 - CCI-000162 - SRG-OS-000462-GPOS-00206 - SRG-OS-000475-GPOS-00220 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - OL09-00-008000 - SV-271885r1092367_rule + SRG-OS-000462-GPOS-00206 + SRG-OS-000475-GPOS-00220 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + OL09-00-008000 + SV-271885r1092367_rule If modification of login UIDs is not prevented, they can be changed by unprivileged users and make auditing complicated or impossible. # Remediation is applicable only in certain platforms @@ -119564,7 +136618,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -119572,7 +136628,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -119588,12 +136646,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -119612,8 +136674,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/selinux/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -119641,7 +136705,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -119649,7 +136715,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -119665,12 +136733,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done @@ -119697,8 +136769,9 @@ fi - reboot_required - restrict_strategy -- name: Check if watch rule for /etc/selinux/ already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Mandatory Access Controls - Check if + watch rule for /etc/selinux/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -119722,8 +136795,9 @@ fi - reboot_required - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key MAC-policy - find: +- name: Record Events that Modify the System's Mandatory Access Controls - Search + /etc/audit/rules.d for other rules with specified key MAC-policy + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)MAC-policy$ patterns: '*.rules' @@ -119749,8 +136823,9 @@ fi - reboot_required - restrict_strategy -- name: Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls - Use /etc/audit/rules.d/MAC-policy.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/MAC-policy.rules when: @@ -119774,8 +136849,9 @@ fi - reboot_required - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -119799,8 +136875,9 @@ fi - reboot_required - restrict_strategy -- name: Add watch rule for /etc/selinux/ in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls - Add watch + rule for /etc/selinux/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/selinux/ -p wa -k MAC-policy create: true @@ -119826,8 +136903,9 @@ fi - reboot_required - restrict_strategy -- name: Check if watch rule for /etc/selinux/ already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Mandatory Access Controls - Check if + watch rule for /etc/selinux/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -119851,8 +136929,9 @@ fi - reboot_required - restrict_strategy -- name: Add watch rule for /etc/selinux/ in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls - Add watch + rule for /etc/selinux/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/selinux/ -p wa -k MAC-policy state: present dest: /etc/audit/audit.rules @@ -119886,16 +136965,396 @@ fi + + Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/selinux/ -p wa -k MAC-policy + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/selinux/ -p wa -k MAC-policy + + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + Req-10.5.5 + R73 + 10.3.4 + 10.3 + The system's mandatory access policy (SELinux) should not be +arbitrarily changed by anything other than administrator action. All changes to +MAC policy should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/selinux/" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/MAC-policy.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/MAC-policy.rules" + # If the MAC-policy.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Check if watch rule for /etc/selinux/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Search /etc/audit/rules.d for other rules with specified key MAC-policy + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)MAC-policy$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/MAC-policy.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Use matched file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Add watch rule for /etc/selinux/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /etc/selinux/ -p wa -k MAC-policy + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Check if watch rule for /etc/selinux/ already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Add watch rule for /etc/selinux/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /etc/selinux/ -p wa -k MAC-policy + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following line to a file with suffix .rules in the + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the directory /etc/audit/rules.d: + -w /usr/share/selinux/ -p wa -k MAC-policy + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /usr/share/selinux/ -p wa -k MAC-policy APO10.01 @@ -120003,6 +137462,12 @@ MAC policy should be audited. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -120026,7 +137491,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/usr/share/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -120034,7 +137501,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/usr/share/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -120050,12 +137519,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/usr/share/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /usr/share/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -120074,8 +137547,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/usr/share/selinux/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -120103,7 +137578,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/usr/share/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -120111,7 +137588,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/usr/share/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -120127,12 +137606,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/usr/share/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /usr/share/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done @@ -120140,7 +137623,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -120153,11 +137636,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/usr/share/selinux/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -120175,11 +137659,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key MAC-policy - find: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Search /etc/audit/rules.d for other rules with specified key MAC-policy + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)MAC-policy$ patterns: '*.rules' @@ -120199,11 +137684,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/MAC-policy.rules when: @@ -120221,11 +137707,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Use matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -120243,11 +137730,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /usr/share/selinux/ in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Add watch rule for /usr/share/selinux/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /usr/share/selinux/ -p wa -k MAC-policy create: true @@ -120267,11 +137755,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/usr/share/selinux/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -120289,11 +137778,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /usr/share/selinux/ in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Add watch rule for /usr/share/selinux/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /usr/share/selinux/ -p wa -k MAC-policy state: present dest: /etc/audit/audit.rules @@ -120314,7 +137804,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -120330,13 +137820,15 @@ fi events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in -the directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +the directory /etc/audit/rules.d, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your +system is 64-bit: -a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your +system is 64-bit: -a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export 1 @@ -120384,11 +137876,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -120460,13 +137947,13 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL10 10.2.1.7 @@ -120489,7 +137976,7 @@ do OTHER_FILTERS="" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="mount" - KEY="perm_mod" + KEY="export" SYSCALL_GROUPING="" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -120826,7 +138313,7 @@ fi - restrict_strategy - name: Set architecture for audit mount tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -120855,13 +138342,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -120870,43 +138357,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/export.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/export.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -120918,23 +138406,23 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -120943,17 +138431,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -120965,10 +138454,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present @@ -120998,13 +138487,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -121013,43 +138502,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/export.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/export.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -121061,23 +138551,23 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -121086,17 +138576,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -121108,10 +138599,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present @@ -121150,8 +138641,9 @@ fi If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your system +is 64-bit: -a always,exit -F arch=ARCH -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification -w /etc/issue -p wa -k audit_rules_networkconfig_modification -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification @@ -121161,8 +138653,9 @@ appropriate for your system: If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your system +is 64-bit: -a always,exit -F arch=ARCH -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification -w /etc/issue -p wa -k audit_rules_networkconfig_modification -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification @@ -121286,6 +138779,7 @@ appropriate for your system: RS.AN-4 Req-10.5.5 R73 + 0582 10.3.4 10.3 The network environment should not be modified by anything other @@ -121639,7 +139133,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121647,7 +139143,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121663,12 +139161,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121687,8 +139189,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/issue" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -121716,7 +139220,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121724,7 +139230,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121740,12 +139248,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121771,7 +139283,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue.net" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121779,7 +139293,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue.net $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121795,12 +139311,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue.net$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121819,8 +139339,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/issue.net" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -121848,7 +139370,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue.net" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121856,7 +139380,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue.net $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121872,12 +139398,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue.net$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121903,7 +139433,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/hosts" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121911,7 +139443,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/hosts $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121927,12 +139461,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/hosts$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121951,8 +139489,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/hosts" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -121980,7 +139520,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/hosts" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121988,7 +139530,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/hosts $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -122004,12 +139548,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/hosts$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done @@ -122036,7 +139584,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sysconfig/network" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -122044,7 +139594,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sysconfig/network $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -122060,12 +139612,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sysconfig/network$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -122084,8 +139640,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sysconfig/network" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -122113,7 +139671,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sysconfig/network" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -122121,7 +139681,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sysconfig/network $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -122137,12 +139699,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sysconfig/network$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done @@ -122171,7 +139737,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -122199,7 +139765,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122208,7 +139774,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122217,43 +139783,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_rules_networkconfig_modification.rules - set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122264,7 +139831,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122273,7 +139840,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122282,7 +139849,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122291,17 +139858,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122312,7 +139880,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122343,7 +139911,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122352,7 +139920,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122361,43 +139929,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_rules_networkconfig_modification.rules - set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122408,7 +139977,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122417,7 +139986,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122426,7 +139995,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122435,17 +140004,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122456,7 +140026,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122484,8 +140054,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/issue\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -122510,8 +140081,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -122538,9 +140110,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -122565,8 +140137,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -122591,8 +140164,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/issue -p wa -k audit_rules_networkconfig_modification create: true @@ -122619,8 +140193,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/issue\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -122645,8 +140220,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/issue -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -122674,8 +140250,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue.net already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue.net already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/issue.net\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -122700,8 +140277,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -122728,9 +140306,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -122755,8 +140333,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -122781,8 +140360,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue.net in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue.net in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification create: true @@ -122809,8 +140389,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue.net already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue.net already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/issue.net\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -122835,8 +140416,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue.net in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue.net in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -122864,8 +140446,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/hosts already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/hosts already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/hosts\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -122890,8 +140473,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -122918,9 +140502,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -122945,8 +140529,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -122971,8 +140556,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/hosts in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/hosts in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/hosts -p wa -k audit_rules_networkconfig_modification create: true @@ -122999,8 +140585,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/hosts already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/hosts already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/hosts\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -123025,8 +140612,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/hosts in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/hosts in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/hosts -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -123054,8 +140642,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sysconfig/network already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/sysconfig/network already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sysconfig/network\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -123080,8 +140669,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -123108,9 +140698,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -123135,8 +140725,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -123161,8 +140752,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sysconfig/network in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/sysconfig/network in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification create: true @@ -123189,8 +140781,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sysconfig/network already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/sysconfig/network already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sysconfig/network\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -123215,8 +140808,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sysconfig/network in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/sysconfig/network in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -123251,70 +140845,27 @@ fi - - Record Attempts to Alter Process and Session Initiation Information + + Record Attempts to Alter Process and Session Initiation Information btmp The audit system already collects process information for all -users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing such process information: --w /var/run/utmp -p wa -k session --w /var/log/btmp -p wa -k session --w /var/log/wtmp -p wa -k session +users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/log/btmp -p wa -k session + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for attempted manual -edits of files involved in storing such process information: --w /var/run/utmp -p wa -k session --w /var/log/btmp -p wa -k session --w /var/log/wtmp -p wa -k session +/etc/audit/audit.rules: + +-w /var/log/btmp -p wa -k session - 1 - 11 - 12 - 13 - 14 - 15 - 16 - 19 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 5.4.1.1 - APO10.01 - APO10.03 - APO10.04 - APO10.05 - APO11.04 - APO12.06 - APO13.01 - BAI03.05 - BAI08.02 - DSS01.03 - DSS01.04 - DSS02.02 - DSS02.04 - DSS02.07 - DSS03.01 - DSS03.05 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - MEA01.01 - MEA01.02 - MEA01.03 - MEA01.04 - MEA01.05 - MEA02.01 - 3.1.7 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -123322,87 +140873,28 @@ edits of files involved in storing such process information: 164.312(b) 164.312(d) 164.312(e) - 4.2.3.10 - 4.3.2.6.7 - 4.3.3.3.9 - 4.3.3.5.8 - 4.3.3.6.6 - 4.3.4.4.7 - 4.3.4.5.6 - 4.3.4.5.7 - 4.3.4.5.8 - 4.4.2.1 - 4.4.2.2 - 4.4.2.4 - SR 1.13 - SR 2.10 - SR 2.11 - SR 2.12 - SR 2.6 - SR 2.8 - SR 2.9 - SR 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 6.1 - SR 6.2 - SR 7.1 - SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - A.11.2.6 - A.12.4.1 - A.12.4.2 - A.12.4.3 - A.12.4.4 - A.12.7.1 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.7 - A.15.2.1 - A.15.2.2 - A.16.1.4 - A.16.1.5 - A.16.1.7 - A.6.2.1 - A.6.2.2 - AU-2(d) AU-12(c) - CM-6(a) - DE.AE-3 - DE.AE-5 - DE.CM-1 - DE.CM-3 - DE.CM-7 - ID.SC-4 - PR.AC-3 - PR.PT-1 - PR.PT-4 - RS.AN-1 - RS.AN-4 - Req-10.2.3 - SRG-APP-000505-CTR-001285 + AU-12.1(iv) + SRG-OS-000472-GPOS-00217 R73 A.3.SEC-OL1 + 0582 + 0846 10.2.1.3 10.2.1 10.2 Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -123426,139 +140918,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - -# If the audit is 'augenrules', then check if rule is already defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. -readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/run/utmp" /etc/audit/rules.d/*.rules) - -# For each of the matched entries -for match in "${matches[@]}" -do - # Extract filepath from the match - rulesd_audit_file=$(echo $match | cut -f1 -d ':') - # Append that path into list of files for inspection - files_to_inspect+=("$rulesd_audit_file") -done -# Case when particular audit rule isn't defined yet -if [ "${#files_to_inspect[@]}" -eq "0" ] -then - # Append '/etc/audit/rules.d/session.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/session.rules" - # If the session.rules file doesn't exist yet, create it with correct permissions - if [ ! -e "$key_rule_file" ] - then - touch "$key_rule_file" - chmod 0600 "$key_rule_file" - fi - files_to_inspect+=("$key_rule_file") -fi - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - - -# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# into the list of files to be inspected -files_to_inspect+=('/etc/audit/audit.rules') - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present if grep -q -P -- "^[\s]*-w[\s]+/var/log/btmp" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -123566,7 +140928,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/btmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -123582,12 +140946,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/btmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/btmp -p wa -k session" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -123606,8 +140974,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/btmp" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -123635,7 +141005,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/btmp" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -123643,7 +141015,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/btmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -123659,144 +141033,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/btmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/btmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - -# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# into the list of files to be inspected -files_to_inspect+=('/etc/audit/audit.rules') - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - -# If the audit is 'augenrules', then check if rule is already defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. -readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/wtmp" /etc/audit/rules.d/*.rules) - -# For each of the matched entries -for match in "${matches[@]}" -do - # Extract filepath from the match - rulesd_audit_file=$(echo $match | cut -f1 -d ':') - # Append that path into list of files for inspection - files_to_inspect+=("$rulesd_audit_file") -done -# Case when particular audit rule isn't defined yet -if [ "${#files_to_inspect[@]}" -eq "0" ] -then - # Append '/etc/audit/rules.d/session.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/session.rules" - # If the session.rules file doesn't exist yet, create it with correct permissions - if [ ! -e "$key_rule_file" ] - then - touch "$key_rule_file" - chmod 0600 "$key_rule_file" - fi - files_to_inspect+=("$key_rule_file") -fi - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" fi done @@ -123804,217 +141050,25 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/run/utmp already exists in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ - patterns: '*.rules' - register: find_existing_watch_rules_d - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Search /etc/audit/rules.d for other rules with specified key session - find: - paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)session$ - patterns: '*.rules' - register: find_watch_key - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use /etc/audit/rules.d/session.rules as the recipient for the rule - set_fact: - all_files: - - /etc/audit/rules.d/session.rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use matched file as the recipient for the rule - set_fact: - all_files: - - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/run/utmp in /etc/audit/rules.d/ - lineinfile: - path: '{{ all_files[0] }}' - line: -w /var/run/utmp -p wa -k session - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/run/utmp already exists in /etc/audit/audit.rules - find: - paths: /etc/audit/ - contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ - patterns: audit.rules - register: find_existing_watch_audit_rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/run/utmp in /etc/audit/audit.rules - lineinfile: - line: -w /var/run/utmp -p wa -k session - state: present - dest: /etc/audit/audit.rules - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/log/btmp already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Check if watch rule for /var/log/btmp already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/btmp\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -124023,24 +141077,21 @@ fi - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key session - find: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Search /etc/audit/rules.d for other rules with specified key session + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)session$ patterns: '*.rules' @@ -124051,24 +141102,21 @@ fi - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/session.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Use /etc/audit/rules.d/session.rules as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/session.rules when: @@ -124077,24 +141125,21 @@ fi - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -124103,24 +141148,21 @@ fi - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/btmp in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Add watch rule for /var/log/btmp in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /var/log/btmp -p wa -k session create: true @@ -124131,24 +141173,21 @@ fi - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/btmp already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Check if watch rule for /var/log/btmp already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/btmp\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -124157,24 +141196,21 @@ fi - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/btmp in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Add watch rule for /var/log/btmp in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /var/log/btmp -p wa -k session state: present dest: /etc/audit/audit.rules @@ -124186,259 +141222,858 @@ fi - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/log/wtmp already exists in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ - patterns: '*.rules' - register: find_existing_watch_rules_d - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Search /etc/audit/rules.d for other rules with specified key session - find: - paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)session$ - patterns: '*.rules' - register: find_watch_key - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use /etc/audit/rules.d/session.rules as the recipient for the rule - set_fact: - all_files: - - /etc/audit/rules.d/session.rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use matched file as the recipient for the rule - set_fact: - all_files: - - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/log/wtmp in /etc/audit/rules.d/ - lineinfile: - path: '{{ all_files[0] }}' - line: -w /var/log/wtmp -p wa -k session - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/log/wtmp already exists in /etc/audit/audit.rules - find: - paths: /etc/audit/ - contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ - patterns: audit.rules - register: find_existing_watch_audit_rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/log/wtmp in /etc/audit/audit.rules - lineinfile: - line: -w /var/log/wtmp -p wa -k session - state: present - dest: /etc/audit/audit.rules - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy - + + + + + + + + Record Attempts to Alter Process and Session Initiation Information utmp + The audit system already collects process information for all +users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/run/utmp -p wa -k session + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/run/utmp -p wa -k session + + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + AU-12(c) + AU-12.1(iv) + SRG-OS-000472-GPOS-00217 + R73 + A.3.SEC-OL1 + 0582 + 0846 + 10.2.1.3 + 10.2.1 + 10.2 + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/run/utmp" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/session.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/session.rules" + # If the session.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Check if watch rule for /var/run/utmp already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Search /etc/audit/rules.d for other rules with specified key session + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)session$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Use /etc/audit/rules.d/session.rules as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/session.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Add watch rule for /var/run/utmp in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/run/utmp -p wa -k session + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Check if watch rule for /var/run/utmp already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Add watch rule for /var/run/utmp in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/run/utmp -p wa -k session + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information wtmp + The audit system already collects process information for all +users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/log/wtmp -p wa -k session + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/log/wtmp -p wa -k session + + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + AU-12(c) + AU-12.1(iv) + SRG-OS-000472-GPOS-00217 + R73 + A.3.SEC-OL1 + 0582 + 0846 + 10.2.1.3 + 10.2.1 + 10.2 + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/wtmp" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/session.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/session.rules" + # If the session.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Check if watch rule for /var/log/wtmp already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Search /etc/audit/rules.d for other rules with specified key session + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)session$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Use /etc/audit/rules.d/session.rules as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/session.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Add watch rule for /var/log/wtmp in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/log/wtmp -p wa -k session + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Check if watch rule for /var/log/wtmp already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Add watch rule for /var/log/wtmp in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/log/wtmp -p wa -k session + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers At a minimum, the audit system should collect administrator actions -for all users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: +for all users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /etc/sudoers -p wa -k actions + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /etc/sudoers -p wa -k actions - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 - OL09-00-000500 - SV-271527r1092474_rule + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + OL09-00-000500 + SV-271527r1092474_rule The actions taken by system administrators should be audited to keep a record of what was executed on the system, as well as, for accountability purposes. Editing the sudoers file may be sign of an attacker trying to @@ -124448,6 +142083,12 @@ files mitigates this risk. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -124471,7 +142112,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124479,7 +142122,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124495,12 +142140,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -124519,8 +142168,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -124548,7 +142199,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124556,7 +142209,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124572,12 +142227,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done @@ -124597,8 +142256,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Check + if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -124615,8 +142275,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Search + /etc/audit/rules.d for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -124635,8 +142296,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -124653,8 +142315,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -124671,8 +142334,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Add watch + rule for /etc/sudoers in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers -p wa -k actions create: true @@ -124691,8 +142355,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Check + if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -124709,8 +142374,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Add watch + rule for /etc/sudoers in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -124740,47 +142406,44 @@ fi Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ At a minimum, the audit system should collect administrator actions -for all users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: +for all users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /etc/sudoers.d/ -p wa -k actions + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /etc/sudoers.d/ -p wa -k actions - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 - OL09-00-000505 - SV-271528r1092476_rule + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + OL09-00-000505 + SV-271528r1092476_rule The actions taken by system administrators should be audited to keep a record of what was executed on the system, as well as, for accountability purposes. Editing the sudoers file may be sign of an attacker trying to @@ -124790,6 +142453,12 @@ files mitigates this risk. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -124813,7 +142482,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124821,7 +142492,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124837,12 +142510,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -124861,8 +142538,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers.d/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -124890,7 +142569,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124898,7 +142579,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124914,12 +142597,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done @@ -124939,8 +142626,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Check + if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -124957,8 +142645,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Search + /etc/audit/rules.d for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -124977,8 +142666,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Use + /etc/audit/rules.d/actions.rules as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -124995,8 +142685,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Use + matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -125013,8 +142704,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Add + watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers.d/ -p wa -k actions create: true @@ -125033,8 +142725,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Check + if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -125051,8 +142744,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Add + watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers.d/ -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -125100,24 +142794,22 @@ If both the "b32" and "b64" audit rules for "SUID" files are not defined, this i If both the "b32" and "b64" audit rules for "SGID" files are not defined, this is a finding. Note that these rules can be configured in a number of ways while still achieving the desired effect. - CCI-002233 - CCI-002234 CM-5(1) AU-7(a) AU-7(b) AU-8(b) AU-12(3) AC-6(9) - SRG-OS-000326-GPOS-00126 - SRG-OS-000327-GPOS-00127 - SRG-APP-000343-CTR-000780 - SRG-APP-000381-CTR-000905 - SRG-OS-000755-GPOS-00220 + SRG-OS-000326-GPOS-00126 + SRG-OS-000327-GPOS-00127 + SRG-APP-000343-CTR-000780 + SRG-APP-000381-CTR-000905 + SRG-OS-000755-GPOS-00220 10.2.1.2 10.2.1 10.2 - OL09-00-000715 - SV-271570r1092558_rule + OL09-00-000715 + SV-271570r1092558_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised information system accounts, is a serious and ongoing concern @@ -125139,7 +142831,9 @@ do AUID_FILTERS="" SYSCALL="execve" + KEY="setuid" + SYSCALL_GROUPING="" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a @@ -125457,7 +143151,9 @@ do AUID_FILTERS="" SYSCALL="execve" + KEY="setgid" + SYSCALL_GROUPING="" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a @@ -125942,18 +143638,40 @@ fi Ensure auditd Collects System Administrator Actions - At a minimum, the audit system should collect administrator actions -for all users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: --w /etc/sudoers -p wa -k actions --w /etc/sudoers.d/ -p wa -k actions + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/sudoers -p wa -k actions + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: --w /etc/sudoers -p wa -k actions --w /etc/sudoers.d/ -p wa -k actions +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/sudoers -p wa -k actions + + + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/sudoers.d/ -p wa -k actions + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/sudoers.d/ -p wa -k actions 1 11 @@ -126002,12 +143720,6 @@ utility to read audit rules during daemon startup, add the following line to MEA01.05 MEA02.01 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -126113,34 +143825,35 @@ utility to read audit rules during daemon startup, add the following line to RS.AN-4 Req-10.2.2 Req-10.2.5.b - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000026-CTR-000070 - SRG-APP-000027-CTR-000075 - SRG-APP-000028-CTR-000080 - SRG-APP-000291-CTR-000675 - SRG-APP-000292-CTR-000680 - SRG-APP-000293-CTR-000685 - SRG-APP-000294-CTR-000690 - SRG-APP-000319-CTR-000745 - SRG-APP-000320-CTR-000750 - SRG-APP-000509-CTR-001305 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000026-CTR-000070 + SRG-APP-000027-CTR-000075 + SRG-APP-000028-CTR-000080 + SRG-APP-000291-CTR-000675 + SRG-APP-000292-CTR-000680 + SRG-APP-000293-CTR-000685 + SRG-APP-000294-CTR-000690 + SRG-APP-000319-CTR-000745 + SRG-APP-000320-CTR-000750 + SRG-APP-000509-CTR-001305 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 @@ -126151,6 +143864,7 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -126174,7 +143888,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126182,7 +143898,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126198,12 +143916,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -126222,8 +143944,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -126251,7 +143975,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126259,7 +143985,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126275,12 +144003,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -126306,7 +144038,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126314,7 +144048,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126330,12 +144066,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -126354,8 +144094,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers.d/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -126383,7 +144125,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126391,7 +144135,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126407,12 +144153,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done @@ -126443,8 +144193,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -126472,8 +144223,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers + in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -126504,8 +144256,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -126533,8 +144286,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - Search /etc/audit/rules.d + for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -126564,8 +144318,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -126593,8 +144348,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use matched file as + the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -126622,8 +144378,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers -p wa -k actions create: true @@ -126653,8 +144410,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers.d/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -126682,8 +144440,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers.d/ + in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers.d/ -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -126714,8 +144473,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -126743,8 +144503,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - Search /etc/audit/rules.d + for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -126774,8 +144535,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -126803,8 +144565,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use matched file as + the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -126832,8 +144595,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers.d/ + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers.d/ -p wa -k actions create: true @@ -126898,8 +144662,6 @@ bottom of the /etc/audit/audit.rules file: MEA02.01 3.3.1 3.3.4 - CCI-000140 - CCI-000139 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -126927,10 +144689,10 @@ bottom of the /etc/audit/audit.rules file: SC-24 CM-6(a) PR.PT-1 - SRG-OS-000046-GPOS-00022 - SRG-OS-000047-GPOS-00023 - OL09-00-000820 - SV-271590r1091482_rule + SRG-OS-000046-GPOS-00022 + SRG-OS-000047-GPOS-00023 + OL09-00-000820 + SV-271590r1091482_rule It is critical for the appropriate personnel to be aware if a system is at risk of failing to process audit logs as required. Without this notification, the security personnel may be unaware of an impending failure of @@ -126986,7 +144748,7 @@ fi - always - name: Collect all files from /etc/audit/rules.d with .rules extension - find: + ansible.builtin.find: paths: /etc/audit/rules.d/ patterns: '*.rules' register: find_rules_d @@ -127008,7 +144770,7 @@ fi - restrict_strategy - name: Remove the -f option from all Audit config files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item }}' regexp: ^\s*(?:-f)\s+.*$ state: absent @@ -127032,7 +144794,7 @@ fi - restrict_strategy - name: Add Audit -f option into /etc/audit/rules.d/immutable.rules and /etc/audit/audit.rules - lineinfile: + ansible.builtin.lineinfile: path: '{{ item }}' create: true mode: '0600' @@ -127140,11 +144902,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000018 - CCI-000130 - CCI-000172 - CCI-001403 - CCI-002130 4.2.3.10 4.3.2.6.7 4.3.3.2.2 @@ -127222,14 +144979,14 @@ separate rule for each syscall that needs to be checked. For example: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -127250,27 +145007,27 @@ separate rule for each syscall that needs to be checked. For example: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000239-GPOS-00089 - SRG-OS-000241-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000476-GPOS-00221 - SRG-APP-000026-CTR-000070 - SRG-APP-000027-CTR-000075 - SRG-APP-000028-CTR-000080 - SRG-APP-000291-CTR-000675 - SRG-APP-000292-CTR-000680 - SRG-APP-000293-CTR-000685 - SRG-APP-000294-CTR-000690 - SRG-APP-000319-CTR-000745 - SRG-APP-000320-CTR-000750 - SRG-APP-000509-CTR-001305 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000239-GPOS-00089 + SRG-OS-000241-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000476-GPOS-00221 + SRG-APP-000026-CTR-000070 + SRG-APP-000027-CTR-000075 + SRG-APP-000028-CTR-000080 + SRG-APP-000291-CTR-000675 + SRG-APP-000292-CTR-000680 + SRG-APP-000293-CTR-000685 + SRG-APP-000294-CTR-000690 + SRG-APP-000319-CTR-000745 + SRG-APP-000320-CTR-000750 + SRG-APP-000509-CTR-001305 In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -127301,7 +145058,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127309,7 +145068,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127325,12 +145086,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127349,8 +145114,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/group" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127378,7 +145145,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127386,7 +145155,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127402,12 +145173,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127433,7 +145208,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127441,7 +145218,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127457,12 +145236,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127481,8 +145264,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/passwd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127510,7 +145295,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127518,7 +145305,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127534,12 +145323,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127565,7 +145358,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127573,7 +145368,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127589,12 +145386,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127613,8 +145414,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/gshadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127642,7 +145445,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127650,7 +145455,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127666,12 +145473,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127697,7 +145508,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127705,7 +145518,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127721,12 +145536,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127745,8 +145564,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/shadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127774,7 +145595,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127782,7 +145605,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127798,12 +145623,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127829,7 +145658,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127837,7 +145668,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127853,12 +145686,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127877,8 +145714,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/security/opasswd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127906,7 +145745,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127914,7 +145755,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127930,12 +145773,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -127952,23 +145799,22 @@ fi Record Events that Modify User/Group Information - /etc/group - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/group -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/group -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/group -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/group -p wa -k audit_rules_usergroup_modification 1 11 @@ -128017,17 +145863,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -128112,14 +145947,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -128140,31 +145975,32 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000510 - SV-271529r1092478_rule + OL09-00-000510 + SV-271529r1092478_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -128173,6 +146009,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -128196,7 +146037,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128204,7 +146047,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128220,12 +146065,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -128244,8 +146093,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/group" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -128273,7 +146124,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128281,7 +146134,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128297,12 +146152,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -128310,7 +146169,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -128330,11 +146189,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/group already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/group - Check if watch + rule for /etc/group already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/group\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -128359,11 +146219,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/group - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -128390,12 +146251,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/group - Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -128420,11 +146281,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/group - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -128449,11 +146311,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/group in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/group - Add watch + rule for /etc/group in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/group -p wa -k audit_rules_usergroup_modification create: true @@ -128480,11 +146343,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/group already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/group - Check if watch + rule for /etc/group already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/group\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -128509,11 +146373,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/group in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/group - Add watch + rule for /etc/group in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/group -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -128541,7 +146406,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -128553,23 +146418,22 @@ fi Record Events that Modify User/Group Information - /etc/gshadow - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/gshadow -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/gshadow -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/gshadow -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/gshadow -p wa -k audit_rules_usergroup_modification 1 11 @@ -128618,17 +146482,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -128713,14 +146566,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -128741,31 +146594,32 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000515 - SV-271530r1092480_rule + OL09-00-000515 + SV-271530r1092480_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -128774,6 +146628,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -128797,7 +146656,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128805,7 +146666,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128821,12 +146684,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -128845,8 +146712,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/gshadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -128874,7 +146743,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128882,7 +146753,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128898,12 +146771,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -128911,7 +146788,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -128931,11 +146808,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/gshadow already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Check if + watch rule for /etc/gshadow already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/gshadow\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -128960,11 +146838,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -128991,12 +146870,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -129021,11 +146900,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -129050,11 +146930,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/gshadow in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Add watch + rule for /etc/gshadow in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification create: true @@ -129081,11 +146962,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/gshadow already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Check if + watch rule for /etc/gshadow already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/gshadow\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -129110,11 +146992,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/gshadow in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Add watch + rule for /etc/gshadow in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -129142,7 +147025,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -129154,23 +147037,22 @@ fi Record Events that Modify User/Group Information - /etc/security/opasswd - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification 1 11 @@ -129219,17 +147101,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -129314,14 +147185,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -129342,33 +147213,34 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000520 - SV-271531r1092482_rule + OL09-00-000520 + SV-271531r1092482_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -129377,6 +147249,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -129400,7 +147277,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -129408,7 +147287,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -129424,12 +147305,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -129448,8 +147333,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/security/opasswd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -129477,7 +147364,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -129485,7 +147374,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -129501,12 +147392,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -129514,7 +147409,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -129534,11 +147429,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/security/opasswd already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Check if watch rule for /etc/security/opasswd already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/security/opasswd\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -129563,11 +147459,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -129594,12 +147491,13 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient for the rule - set_fact: + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -129624,11 +147522,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -129653,11 +147552,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/security/opasswd in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Add watch rule for /etc/security/opasswd in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification create: true @@ -129684,11 +147584,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/security/opasswd already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Check if watch rule for /etc/security/opasswd already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/security/opasswd\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -129713,11 +147614,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/security/opasswd in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Add watch rule for /etc/security/opasswd in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -129745,7 +147647,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -129757,23 +147659,22 @@ fi Record Events that Modify User/Group Information - /etc/passwd - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/passwd -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/passwd -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/passwd -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/passwd -p wa -k audit_rules_usergroup_modification 1 11 @@ -129822,17 +147723,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -129917,14 +147807,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -129945,36 +147835,37 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-OS-000274-GPOS-00104 - SRG-OS-000275-GPOS-00105 - SRG-OS-000276-GPOS-00106 - SRG-OS-000277-GPOS-00107 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-OS-000274-GPOS-00104 + SRG-OS-000275-GPOS-00105 + SRG-OS-000276-GPOS-00106 + SRG-OS-000277-GPOS-00107 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000525 - SV-271532r1092484_rule + OL09-00-000525 + SV-271532r1092484_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -129983,6 +147874,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -130006,7 +147902,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130014,7 +147912,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130030,12 +147930,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -130053,9 +147957,11 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/passwd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -130067,9 +147973,9 @@ done # Case when particular audit rule isn't defined yet if [ "${#files_to_inspect[@]}" -eq "0" ] then - # Append '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/audit_rules_usergroup_modification.rules" - # If the audit_rules_usergroup_modification.rules file doesn't exist yet, create it with correct permissions + # Append '/etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules" + # If the audit_rules_usergroup_modification_passwd.rules file doesn't exist yet, create it with correct permissions if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" @@ -130083,7 +147989,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130091,7 +147999,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130107,12 +148017,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd" >> "$audit_rules_file" + fi done @@ -130120,7 +148034,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -130140,11 +148054,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/passwd already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/passwd - Check if + watch rule for /etc/passwd already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/passwd\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -130169,13 +148084,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/passwd - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification_passwd + ansible.builtin.find: paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ + contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification_passwd$ patterns: '*.rules' register: find_watch_key when: @@ -130200,14 +148116,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/passwd - Use /etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - - /etc/audit/rules.d/audit_rules_usergroup_modification.rules + - /etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -130230,11 +148146,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/passwd - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -130259,13 +148176,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/passwd in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/passwd - Add watch + rule for /etc/passwd in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' - line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification + line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd create: true mode: '0600' when: @@ -130290,11 +148208,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/passwd already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/passwd - Check if + watch rule for /etc/passwd already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/passwd\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -130319,12 +148238,13 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/passwd in /etc/audit/audit.rules - lineinfile: - line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification +- name: Record Events that Modify User/Group Information - /etc/passwd - Add watch + rule for /etc/passwd in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd state: present dest: /etc/audit/audit.rules create: true @@ -130351,7 +148271,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -130363,23 +148283,22 @@ fi Record Events that Modify User/Group Information - /etc/shadow - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/shadow -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/shadow -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/shadow -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/shadow -p wa -k audit_rules_usergroup_modification 1 11 @@ -130428,17 +148347,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -130523,14 +148431,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -130551,31 +148459,32 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000530 - SV-271533r1092486_rule + OL09-00-000530 + SV-271533r1092486_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -130584,6 +148493,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -130607,7 +148521,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130615,7 +148531,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130631,12 +148549,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -130655,8 +148577,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/shadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -130684,7 +148608,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130692,7 +148618,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130708,12 +148636,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -130721,7 +148653,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -130741,11 +148673,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/shadow already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/shadow - Check if + watch rule for /etc/shadow already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/shadow\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -130770,11 +148703,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/shadow - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -130801,12 +148735,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/shadow - Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -130831,11 +148765,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/shadow - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -130860,11 +148795,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/shadow in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/shadow - Add watch + rule for /etc/shadow in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification create: true @@ -130891,11 +148827,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/shadow already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/shadow - Check if + watch rule for /etc/shadow already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/shadow\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -130920,11 +148857,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/shadow in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/shadow - Add watch + rule for /etc/shadow in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -130952,7 +148890,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -130962,6 +148900,358 @@ fi + + Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/spool/cron -p wa -k cronjobs + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/spool/cron -p wa -k cronjobs + + SRG-OS-000363-GPOS-00150 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 + OL09-00-002584 + SV-278952r1135407_rule + In addition to auditing new user and group accounts, these watches +will alert the system administrator(s) to any modifications. Any unexpected +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/spool/cron" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/spool/cron $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/spool/cron$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/spool/cron -p wa -k cronjobs" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/cronjobs.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/spool/cron" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/cronjobs.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/cronjobs.rules" + # If the cronjobs.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/spool/cron" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/spool/cron $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/spool/cron$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/spool/cron -p wa -k cronjobs" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Check if watch + rule for /var/spool/cron already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/spool/cron\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Search /etc/audit/rules.d + for other rules with specified key cronjobs + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)cronjobs$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Use /etc/audit/rules.d/cronjobs.rules + as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/cronjobs.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Add watch + rule for /var/spool/cron in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/spool/cron -p wa -k cronjobs + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Check if watch + rule for /var/spool/cron already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/spool/cron\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Add watch + rule for /var/spool/cron in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/spool/cron -p wa -k cronjobs + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + Record Attempts to perform maintenance activities The Oracle Linux 9 operating system must generate audit records for @@ -130972,13 +149262,28 @@ Verify the operating system audits activities performed during nonlocal maintenance and diagnostic sessions. Run the following command: $ sudo auditctl -l | grep sudo.log -w /var/log/sudo.log -p wa -k maintenance + + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/log/sudo.log -p wa -k maintenance + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/log/sudo.log -p wa -k maintenance - CCI-000172 - CCI-002884 Req-10.2.2 Req-10.2.5.b - SRG-OS-000392-GPOS-00172 - SRG-OS-000471-GPOS-00215 + SRG-OS-000392-GPOS-00172 + SRG-OS-000471-GPOS-00215 R73 A.3.SEC-OL7 10.2.1.3 @@ -131009,6 +149314,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -131032,7 +149341,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/sudo.log" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -131040,7 +149351,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/sudo.log $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -131056,12 +149369,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/sudo.log$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/sudo.log -p wa -k logins" >> "$audit_rules_file" + + echo "-w /var/log/sudo.log -p wa -k maintenance" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -131079,9 +149396,11 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/maintenance.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/sudo.log" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -131093,9 +149412,9 @@ done # Case when particular audit rule isn't defined yet if [ "${#files_to_inspect[@]}" -eq "0" ] then - # Append '/etc/audit/rules.d/logins.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/logins.rules" - # If the logins.rules file doesn't exist yet, create it with correct permissions + # Append '/etc/audit/rules.d/maintenance.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/maintenance.rules" + # If the maintenance.rules file doesn't exist yet, create it with correct permissions if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" @@ -131109,7 +149428,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/sudo.log" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -131117,7 +149438,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/sudo.log $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -131133,12 +149456,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/sudo.log$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/sudo.log -p wa -k logins" >> "$audit_rules_file" + + echo "-w /var/log/sudo.log -p wa -k maintenance" >> "$audit_rules_file" + fi done @@ -131146,7 +149473,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -131159,11 +149486,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/sudo.log already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to perform maintenance activities - Check if watch rule for + /var/log/sudo.log already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/sudo.log\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -131181,13 +149509,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to perform maintenance activities - Search /etc/audit/rules.d + for other rules with specified key maintenance + ansible.builtin.find: paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)logins$ + contains: ^.*(?:-F key=|-k\s+)maintenance$ patterns: '*.rules' register: find_watch_key when: @@ -131205,13 +149534,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to perform maintenance activities - Use /etc/audit/rules.d/maintenance.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - - /etc/audit/rules.d/logins.rules + - /etc/audit/rules.d/maintenance.rules when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -131227,11 +149557,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to perform maintenance activities - Use matched file as the + recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -131249,13 +149580,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/sudo.log in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to perform maintenance activities - Add watch rule for /var/log/sudo.log + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' - line: -w /var/log/sudo.log -p wa -k logins + line: -w /var/log/sudo.log -p wa -k maintenance create: true mode: '0600' when: @@ -131273,11 +149605,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/sudo.log already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to perform maintenance activities - Check if watch rule for + /var/log/sudo.log already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/sudo.log\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -131295,12 +149628,13 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/sudo.log in /etc/audit/audit.rules - lineinfile: - line: -w /var/log/sudo.log -p wa -k logins +- name: Record Attempts to perform maintenance activities - Add watch rule for /var/log/sudo.log + in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/log/sudo.log -p wa -k maintenance state: present dest: /etc/audit/audit.rules create: true @@ -131320,7 +149654,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -131335,7 +149669,8 @@ fi The audit system should collect access events to read audit log directory. The following audit rule will assure that access to audit log directory are collected. --a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +Set ARCH to either b32 for 32-bit system, or have two lines for both b32 and b64 in case your system is 64-bit. +-a always,exit -F arch=ARCH -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the rule to a file with suffix .rules in the directory @@ -131354,14 +149689,18 @@ Auditing these events could serve as evidence of potential system compromise.'# Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F dir=/var/log/audit/ -F perm=r" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="access-audit-trail" SYSCALL_GROUPING="" +[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") + +for ARCH in "${RULE_ARCHS[@]}" +do # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' -unset syscall_a + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + unset syscall_a unset syscall_grouping unset syscall_string unset syscall @@ -131520,7 +149859,7 @@ if [ "$skip" -ne 0 ]; then sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" fi fi -unset syscall_a + unset syscall_a unset syscall_grouping unset syscall_string unset syscall @@ -131666,6 +150005,7 @@ if [ "$skip" -ne 0 ]; then sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" fi fi +done else >&2 echo 'Remediation is not applicable, nothing was done' @@ -131688,63 +150028,87 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /var/log/audit +- name: Record Access Events to Audit Log Directory - Set architecture for audit tasks + ansible.builtin.set_fact: + audit_arch: b64 + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture + == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" + tags: + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - directory_access_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Access Events to Audit Log Directory - Perform remediation of Audit + rules for /var/log/audit block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d - contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F - dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ patterns: '*.rules' register: find_command loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access-audit-trail.rules - set_fact: audit_file="/etc/audit/rules.d/access-audit-trail.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access-audit-trail.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (?:-k |-F key=)\w+) line: \1\2\3{{ missing_syscalls | join("\3") }}\4 @@ -131754,45 +150118,46 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - line: -a always,exit{{ syscalls | join(',') }} -F dir=/var/log/audit/ -F perm=r - -F auid>=1000 -F auid!=unset -F key=access-audit-trail + line: -a always,exit -F arch=b32{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit - contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F - dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ patterns: audit.rules register: find_command loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( - -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 + -F auid!=unset (?:-k |-F key=)\w+) line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present @@ -131800,10 +150165,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - line: -a always,exit{{ syscalls | join(',') }} -F dir=/var/log/audit/ -F perm=r - -F auid>=1000 -F auid!=unset -F key=access-audit-trail + line: -a always,exit -F arch=b32{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail create: true mode: g-rwx,o-rwx state: present @@ -131824,6 +150189,147 @@ fi - medium_severity - no_reboot_needed - restrict_strategy + +- name: Record Access Events to Audit Log Directory - Perform remediation of Audit + rules for /var/log/audit for x86_64 platform + block: + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: [] + syscall_grouping: [] + + - name: Check existence of in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/access-audit-trail.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access-audit-trail.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F + auid>=1000 -F auid!=unset (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: [] + syscall_grouping: [] + + - name: Check existence of in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 + -F auid!=unset (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - audit_arch == "b64" + tags: + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - directory_access_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy @@ -131837,7 +150343,10 @@ fi All audit directories must be group owned by root user. By default, the path for audit log is /var/log/audit/. To properly set the group owner of /var/log/audit, run the command: -$ sudo chgrp root /var/log/audit + + $ sudo chgrp root /var/log/audit + + If log_group in /etc/audit/auditd.conf is set to a group other than the root group account, change the group ownership of the audit directories to this specific group. @@ -131871,10 +150380,6 @@ group account, change the group ownership of the audit directories to this speci DSS06.02 MEA02.01 3.3.1 - CCI-000163 - CCI-000164 - CCI-001314 - CCI-000162 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -131936,12 +150441,12 @@ group account, change the group ownership of the audit directories to this speci RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - OL09-00-000785 - SV-271583r1091461_rule + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + OL09-00-000785 + SV-271583r1091461_rule Unauthorized disclosure of audit records can reveal system and configuration data to attackers, thus compromising its confidentiality. # Remediation is applicable only in certain platforms @@ -132045,7 +150550,8 @@ fi All audit directories must be owned by root user. By default, the path for audit log is /var/log/audit/. To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit + + $ sudo chown root /var/log/audit 1 11 @@ -132077,10 +150583,6 @@ To properly set the owner of /var/log/audit, run the comm DSS06.02 MEA02.01 3.3.1 - CCI-000163 - CCI-000164 - CCI-001314 - CCI-000162 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132142,12 +150644,12 @@ To properly set the owner of /var/log/audit, run the comm RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - OL09-00-000790 - SV-271584r1091464_rule + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + OL09-00-000790 + SV-271584r1091464_rule Unauthorized disclosure of audit records can reveal system and configuration data to attackers, thus compromising its confidentiality. # Remediation is applicable only in certain platforms @@ -132275,9 +150777,6 @@ Otherwise, change the mode of the audit log files with the following command: DSS05.07 DSS06.02 MEA02.01 - CCI-000162 - CCI-000163 - CCI-000164 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132328,18 +150827,18 @@ Otherwise, change the mode of the audit log files with the following command: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 - CIP-007-3 R6.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 + CIP-007-3 R6.5 CM-6(a) AC-6(1) AU-9 @@ -132350,9 +150849,9 @@ Otherwise, change the mode of the audit log files with the following command: PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 A.3.SEC-OL2 If users can write to audit logs, audit trails can be modified or destroyed. # Remediation is applicable only in certain platforms @@ -132394,7 +150893,10 @@ be configured via log_file parameter in /etc/au or, by default, the path for audit log is /var/log/audit/. To properly set the group owner of /var/log/audit/*, run the command: -$ sudo chgrp root /var/log/audit/* + + $ sudo chgrp root /var/log/audit/* + + If log_group in /etc/audit/auditd.conf is set to a group other than the root group account, change the group ownership of the audit logs @@ -132429,10 +150931,6 @@ to this specific group. DSS06.02 MEA02.01 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132494,10 +150992,10 @@ to this specific group. RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 A.3.SEC-OL2 10.3.2 10.3 @@ -132540,8 +151038,7 @@ fi All audit configuration files must be owned by group root. chown :root /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* - CCI-000171 - SRG-OS-000063-GPOS-00032 + SRG-OS-000063-GPOS-00032 A.3.SEC-OL4 Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able @@ -132553,9 +151050,18 @@ to an incident or identify those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi -find -L /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.rules$' -exec chgrp -L 0 {} \; +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.rules$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -132572,9 +151078,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupownership_audit_configuration_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupownership_audit_configuration_newgroup: '0' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_audit_configuration + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - command: find -H /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended - -regex "^.*audit(\.rules|d\.conf)$" + ansible.builtin.command: find -P /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype + posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false @@ -132591,9 +151112,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - file: + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ file_groupownership_audit_configuration_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132609,8 +151131,8 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended - -regex "^.*\.rules$" + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -group + 0 -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false @@ -132627,9 +151149,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - file: + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ file_groupownership_audit_configuration_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132656,13 +151179,16 @@ fi All audit configuration files must be owned by root user. To properly set the owner of /etc/audit/, run the command: -$ sudo chown root /etc/audit/ + + $ sudo chown root /etc/audit/ + + To properly set the owner of /etc/audit/rules.d/, run the command: -$ sudo chown root /etc/audit/rules.d/ + + $ sudo chown root /etc/audit/rules.d/ - CCI-000171 - SRG-OS-000063-GPOS-00032 + SRG-OS-000063-GPOS-00032 A.3.SEC-OL4 Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able @@ -132674,9 +151200,20 @@ to an incident or identify those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi -find -L /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*\.rules$' -exec chown -L 0 {} \; +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /etc/audit/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chown --no-dereference "$newown" {} \; + +find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*\.rules$' -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -132693,9 +151230,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_ownership_audit_configuration_newown variable if represented + by uid + ansible.builtin.set_fact: + file_ownership_audit_configuration_newown: '0' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_audit_configuration + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - command: find -H /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*audit(\.rules|d\.conf)$" + ansible.builtin.command: find -P /etc/audit/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false @@ -132712,9 +151264,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_audit_configuration_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132730,8 +151283,8 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*\.rules$" + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -user + 0 -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false @@ -132748,9 +151301,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_audit_configuration_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132777,10 +151331,14 @@ fi All audit logs must be owned by root user and group. By default, the path for audit log is /var/log/audit/. To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit + + $ sudo chown root /var/log/audit + + To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* + + $ sudo chown root /var/log/audit/* 1 11 @@ -132812,10 +151370,6 @@ To properly set the owner of /var/log/audit/*, run the co DSS06.02 MEA02.01 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132866,15 +151420,15 @@ To properly set the owner of /var/log/audit/*, run the co A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) AU-9(4) @@ -132886,10 +151440,10 @@ To properly set the owner of /var/log/audit/*, run the co RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000118-CTR-000240 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000118-CTR-000240 A.3.SEC-OL2 10.3.2 10.3 @@ -132928,9 +151482,8 @@ fi All audit configuration files permissions must be 640 or more restrictive. chmod 0640 /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* - CCI-000171 AU-12 b - SRG-OS-000063-GPOS-00032 + SRG-OS-000063-GPOS-00032 A.3.SEC-OL4 Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able @@ -132942,9 +151495,9 @@ to an incident or identify those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chmod u-xs,g-xws,o-xwrt {} \; +find -P /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chmod u-xs,g-xws,o-xwrt {} \; -find -L /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*\.rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; +find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*\.rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -132963,8 +151516,8 @@ fi - no_reboot_needed - name: Find /etc/audit/ file(s) - command: find -H /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype - posix-extended -regex "^.*audit(\.rules|d\.conf)$" + ansible.builtin.command: find -P /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type + f -regextype posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false @@ -132982,7 +151535,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/audit/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xws,o-xwrt state: file @@ -133001,7 +151554,7 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) - command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false @@ -133020,7 +151573,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/audit/rules.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xws,o-xwrt state: file @@ -133086,10 +151639,6 @@ By default, audit_log_file is "/var/log/audit/audit.log".DSS06.02 MEA02.01 3.3.1 - CCI-000163 - CCI-000164 - CCI-001314 - CCI-000162 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -133140,15 +151689,15 @@ By default, audit_log_file is "/var/log/audit/audit.log".A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-007-3 R2.1 - CIP-007-3 R2.2 - CIP-007-3 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-007-3 R2.1 + CIP-007-3 R2.2 + CIP-007-3 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.2 CM-6(a) AC-6(1) AU-9(4) @@ -133160,16 +151709,16 @@ By default, audit_log_file is "/var/log/audit/audit.log".RS.AN-1 RS.AN-4 Req-10.5 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 A.3.SEC-OL2 10.3.1 10.3 - OL09-00-000795 - SV-271585r1091467_rule + OL09-00-000795 + SV-271585r1091467_rule If users can write to audit logs, audit trails can be modified or destroyed. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -133208,8 +151757,10 @@ fi - restrict_strategy - name: Get audit log files - command: grep -iw ^log_file /etc/audit/auditd.conf + ansible.builtin.command: grep -iw ^log_file /etc/audit/auditd.conf failed_when: false + changed_when: false + check_mode: false register: log_file_exists when: - '"audit" in ansible_facts.packages' @@ -133232,8 +151783,10 @@ fi - restrict_strategy - name: Parse log file line - command: awk -F '=' '/^log_file/ {print $2}' /etc/audit/auditd.conf + ansible.builtin.command: awk -F '=' '/^log_file/ {print $2}' /etc/audit/auditd.conf register: log_file_line + changed_when: false + check_mode: false when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -133256,7 +151809,7 @@ fi - restrict_strategy - name: Set default log_file if not set - set_fact: + ansible.builtin.set_fact: log_file: /var/log/audit/audit.log when: - '"audit" in ansible_facts.packages' @@ -133281,7 +151834,7 @@ fi - restrict_strategy - name: Set log_file from log_file_line if not set already - set_fact: + ansible.builtin.set_fact: log_file: '{{ log_file_line.stdout | trim }}' when: - '"audit" in ansible_facts.packages' @@ -133306,7 +151859,7 @@ fi - restrict_strategy - name: Apply mode to log file - file: + ansible.builtin.file: path: '{{ log_file }}' mode: 384 failed_when: false @@ -133347,12 +151900,16 @@ calls. Additionally, these rules can be configured in a number of ways while still achieving the desired effect. An example of this is that the "-S" calls could be split up and placed on separate lines, however, this is less efficient. Add the following to /etc/audit/audit.rules: + -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod + -a always,exit -F arch=b32 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod If your system is 64 bit then these lines should be duplicated and the arch=b32 replaced with arch=b64 as follows: + -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod + -a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -133422,11 +151979,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -133497,29 +152049,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 + 0582 10.3.4 10.3 - OL09-00-000640 - SV-271555r1092530_rule + OL09-00-000640 + SV-271555r1092530_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -133874,7 +152427,7 @@ fi - restrict_strategy - name: Set architecture for audit chmod tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -133903,7 +152456,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -133912,7 +152465,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -133921,43 +152474,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -133969,7 +152523,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -133979,7 +152533,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -133988,7 +152542,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -133997,17 +152551,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -134019,7 +152574,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134052,7 +152607,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -134061,7 +152616,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134070,43 +152625,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -134118,7 +152674,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134128,7 +152684,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -134137,7 +152693,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134146,17 +152702,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -134168,7 +152725,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134271,11 +152828,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -134346,30 +152898,31 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 + 0582 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -134724,7 +153277,7 @@ fi - restrict_strategy - name: Set architecture for audit chown tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -134753,7 +153306,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134763,7 +153316,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134772,43 +153325,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -134820,7 +153374,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134830,7 +153384,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134840,7 +153394,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134849,17 +153403,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -134871,7 +153426,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134904,7 +153459,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134914,7 +153469,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134923,43 +153478,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -134971,7 +153527,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134981,7 +153537,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134991,7 +153547,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135000,17 +153556,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -135022,7 +153579,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135125,11 +153682,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -135200,29 +153752,29 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000640 - SV-271555r1092530_rule + OL09-00-000640 + SV-271555r1092530_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -135576,7 +154128,7 @@ fi - restrict_strategy - name: Set architecture for audit fchmod tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -135604,7 +154156,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135613,7 +154165,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135622,43 +154174,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -135670,7 +154223,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135680,7 +154233,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135689,7 +154242,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135698,17 +154251,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -135720,7 +154274,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135752,7 +154306,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135761,7 +154315,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135770,43 +154324,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -135818,7 +154373,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135828,7 +154383,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135837,7 +154392,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135846,17 +154401,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -135868,7 +154424,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135970,11 +154526,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -136045,29 +154596,29 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000640 - SV-271555r1092530_rule + OL09-00-000640 + SV-271555r1092530_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -136421,7 +154972,7 @@ fi - restrict_strategy - name: Set architecture for audit fchmodat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -136449,7 +155000,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136458,7 +155009,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136467,43 +155018,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -136515,7 +155067,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136525,7 +155077,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136534,7 +155086,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136543,17 +155095,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -136565,7 +155118,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136597,7 +155150,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136606,7 +155159,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136615,43 +155168,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -136663,7 +155217,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136673,7 +155227,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136682,7 +155236,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136691,17 +155245,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -136713,7 +155268,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136818,11 +155373,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -136893,30 +155443,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -137270,7 +155820,7 @@ fi - restrict_strategy - name: Set architecture for audit fchown tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -137298,7 +155848,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137308,7 +155858,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137317,43 +155867,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -137365,7 +155916,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137375,7 +155926,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137385,7 +155936,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137394,17 +155945,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -137416,7 +155968,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137448,7 +156000,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137458,7 +156010,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137467,43 +156019,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -137515,7 +156068,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137525,7 +156078,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137535,7 +156088,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137544,17 +156097,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -137566,7 +156120,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137668,11 +156222,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -137743,30 +156292,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -138120,7 +156669,7 @@ fi - restrict_strategy - name: Set architecture for audit fchownat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -138148,7 +156697,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138158,7 +156707,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138167,43 +156716,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -138215,7 +156765,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138225,7 +156775,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138235,7 +156785,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138244,17 +156794,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -138266,7 +156817,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138298,7 +156849,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138308,7 +156859,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138317,43 +156868,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -138365,7 +156917,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138375,7 +156927,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138385,7 +156937,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138394,17 +156946,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -138416,7 +156969,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138531,11 +157084,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -138606,35 +157154,35 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -138963,6 +157511,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="fremovexattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -138988,7 +157855,7 @@ fi - restrict_strategy - name: Set architecture for audit fremovexattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -139016,7 +157883,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139028,7 +157895,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139037,43 +157904,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -139085,7 +157953,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139095,7 +157963,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139107,7 +157975,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139116,17 +157984,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -139138,7 +158007,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139146,6 +158015,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -139170,7 +158171,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139182,7 +158183,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139191,43 +158192,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -139239,7 +158241,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139249,7 +158251,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139261,7 +158263,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139270,17 +158272,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -139292,7 +158295,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139300,6 +158303,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -139398,11 +158533,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -139473,36 +158603,36 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -139831,6 +158961,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="fsetxattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -139856,7 +159305,7 @@ fi - restrict_strategy - name: Set architecture for audit fsetxattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -139884,7 +159333,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -139896,7 +159345,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139905,43 +159354,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -139953,7 +159403,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139963,7 +159413,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -139975,7 +159425,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139984,17 +159434,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -140006,7 +159457,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140014,6 +159465,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -140038,7 +159621,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -140050,7 +159633,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140059,43 +159642,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -140107,7 +159691,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140117,7 +159701,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -140129,7 +159713,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140138,17 +159722,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -140160,7 +159745,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140168,6 +159753,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -140262,11 +159979,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -140337,30 +160049,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -140715,7 +160427,7 @@ fi - restrict_strategy - name: Set architecture for audit lchown tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -140744,7 +160456,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140754,7 +160466,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140763,43 +160475,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -140811,7 +160524,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140821,7 +160534,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140831,7 +160544,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140840,17 +160553,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -140862,7 +160576,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140895,7 +160609,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140905,7 +160619,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140914,43 +160628,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -140962,7 +160677,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140972,7 +160687,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140982,7 +160697,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140991,17 +160706,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -141013,7 +160729,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141129,11 +160845,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -141204,37 +160915,37 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -141563,6 +161274,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="lremovexattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -141588,7 +161618,7 @@ fi - restrict_strategy - name: Set architecture for audit lremovexattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -141616,7 +161646,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141628,7 +161658,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141637,43 +161667,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -141685,7 +161716,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141695,7 +161726,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141707,7 +161738,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141716,17 +161747,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -141738,7 +161770,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141746,6 +161778,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -141770,7 +161934,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141782,7 +161946,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141791,43 +161955,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -141839,7 +162004,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141849,7 +162014,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141861,7 +162026,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141870,17 +162035,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -141892,7 +162058,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141900,6 +162066,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -141998,11 +162296,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -142073,36 +162366,36 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -142431,6 +162724,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="lsetxattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -142456,7 +163068,7 @@ fi - restrict_strategy - name: Set architecture for audit lsetxattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -142484,7 +163096,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142496,7 +163108,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142505,43 +163117,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -142553,7 +163166,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142563,7 +163176,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142575,7 +163188,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142584,17 +163197,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -142606,7 +163220,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142614,6 +163228,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -142638,7 +163384,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142650,7 +163396,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142659,43 +163405,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -142707,7 +163454,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142717,7 +163464,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142729,7 +163476,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142738,17 +163485,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -142760,7 +163508,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142768,6 +163516,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -142874,11 +163754,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -142949,37 +163824,37 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -143308,6 +164183,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="removexattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -143333,7 +164527,7 @@ fi - restrict_strategy - name: Set architecture for audit removexattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -143361,7 +164555,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143373,7 +164567,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143382,43 +164576,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -143430,7 +164625,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143440,7 +164635,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143452,7 +164647,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143461,17 +164656,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -143483,7 +164679,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143491,6 +164687,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -143515,7 +164843,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143527,7 +164855,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143536,43 +164864,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -143584,7 +164913,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143594,7 +164923,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143606,7 +164935,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143615,17 +164944,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -143637,7 +164967,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143645,6 +164975,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -143743,11 +165205,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -143818,28 +165275,28 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000466-GPOS-00210 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000466-GPOS-00210 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -144168,6 +165625,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="setxattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -144193,7 +165969,7 @@ fi - restrict_strategy - name: Set architecture for audit setxattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -144221,7 +165997,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144233,7 +166009,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144242,43 +166018,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -144290,7 +166067,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144300,7 +166077,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144312,7 +166089,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144321,17 +166098,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -144343,7 +166121,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144351,6 +166129,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -144375,7 +166285,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144387,7 +166297,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144396,43 +166306,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -144444,7 +166355,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144454,7 +166365,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144466,7 +166377,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144475,17 +166386,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -144497,7 +166409,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144505,6 +166417,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -144550,18 +166594,14 @@ utility to read audit rules during daemon startup, add the following line to number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient. - CCI-000172 - CCI-000130 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000840 - SV-271594r1092582_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000840 + SV-271594r1092582_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -144904,13 +166944,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount syscall_grouping: [] - name: Check existence of umount in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144919,43 +166959,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -144967,7 +167008,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144977,13 +167018,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount syscall_grouping: [] - name: Check existence of umount in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144992,17 +167033,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -145014,7 +167056,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145063,19 +167105,15 @@ If the system is 64 bit then also add the following line: number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient. - CCI-000172 - CCI-000130 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 R73 - OL09-00-000845 - SV-271595r1092584_rule + OL09-00-000845 + SV-271595r1092584_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -145421,7 +167459,7 @@ fi - restrict_strategy - name: Set architecture for audit umount2 tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -145441,13 +167479,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145456,43 +167494,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -145504,7 +167543,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145514,13 +167553,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145529,17 +167568,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -145551,7 +167591,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145575,13 +167615,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145590,43 +167630,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -145638,7 +167679,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145648,13 +167689,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145663,17 +167704,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -145685,7 +167727,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145720,33 +167762,34 @@ fi ACL privileged commands for all users and root. Record Any Attempts to Run chacl - At a minimum, the audit system should collect any execution attempt -of the chacl command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - OL09-00-000665 - SV-271560r1092540_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + OL09-00-000665 + SV-271560r1092540_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -145756,12 +167799,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chacl -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -146085,16 +168131,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chacl +- name: Record Any Attempts to Run chacl - Perform remediation of Audit rules for + /usr/bin/chacl block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146103,43 +168150,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chacl -F perm=x -F @@ -146151,7 +168199,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146161,12 +168209,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146175,17 +168223,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset @@ -146197,7 +168246,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146226,31 +168275,32 @@ fi Record Any Attempts to Run setfacl - At a minimum, the audit system should collect any execution attempt -of the setfacl command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000560 - SV-271539r1092498_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000560 + SV-271539r1092498_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -146260,12 +168310,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/setfacl -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -146589,16 +168642,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/setfacl +- name: Record Any Attempts to Run setfacl - Perform remediation of Audit rules for + /usr/bin/setfacl block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146607,43 +168661,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/setfacl -F perm=x @@ -146655,7 +168710,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146665,12 +168720,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146679,17 +168734,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset @@ -146701,7 +168757,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146735,15 +168791,21 @@ fi SELinux privileged commands for all users and root. Record Any Attempts to Run chcon - At a minimum, the audit system should collect any execution attempt -of the chcon command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -146778,11 +168840,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -146821,23 +168878,24 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 - OL09-00-000555 - SV-271538r1092496_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + 0582 + OL09-00-000555 + SV-271538r1092496_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -146852,12 +168910,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chcon -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -147186,16 +169247,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chcon +- name: Record Any Attempts to Run chcon - Perform remediation of Audit rules for + /usr/bin/chcon block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147204,43 +169266,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chcon -F perm=x -F @@ -147252,7 +169315,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147262,12 +169325,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147276,17 +169339,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset @@ -147298,7 +169362,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147332,15 +169396,21 @@ fi Record Any Attempts to Run restorecon - At a minimum, the audit system should collect any execution attempt -of the restorecon command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -147375,8 +169445,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -147415,9 +169483,10 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000392-GPOS-00172 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 + SRG-OS-000392-GPOS-00172 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + 0582 Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -147432,12 +169501,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/restorecon -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -147765,16 +169837,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/restorecon +- name: Record Any Attempts to Run restorecon - Perform remediation of Audit rules + for /usr/sbin/restorecon block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147783,43 +169856,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/restorecon -F perm=x @@ -147831,7 +169905,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147841,12 +169915,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147855,17 +169929,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset @@ -147877,7 +169952,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147910,15 +169985,21 @@ fi Record Any Attempts to Run semanage - At a minimum, the audit system should collect any execution attempt -of the semanage command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -147953,11 +170034,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -147987,14 +170063,14 @@ utility to read audit rules during daemon startup, add the following lines to A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -148005,20 +170081,21 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - OL09-00-000650 - SV-271557r1092534_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + 0582 + OL09-00-000650 + SV-271557r1092534_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -148033,12 +170110,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/semanage -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -148368,16 +170448,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/semanage +- name: Record Any Attempts to Run semanage - Perform remediation of Audit rules for + /usr/sbin/semanage block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148386,43 +170467,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/semanage -F perm=x @@ -148434,7 +170516,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -148444,12 +170526,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148458,17 +170540,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset @@ -148480,7 +170563,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -148515,40 +170598,42 @@ fi Record Any Attempts to Run setfiles - At a minimum, the audit system should collect any execution attempt -of the setfiles command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 AU-2(d) AU-12(c) AC-6(9) CM-6(a) - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - OL09-00-000655 - SV-271558r1092536_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + 0582 + OL09-00-000655 + SV-271558r1092536_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -148563,12 +170648,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/setfiles -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -148896,16 +170984,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/setfiles +- name: Record Any Attempts to Run setfiles - Perform remediation of Audit rules for + /usr/sbin/setfiles block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148914,43 +171003,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setfiles -F perm=x @@ -148962,7 +171052,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -148972,12 +171062,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148986,17 +171076,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset @@ -149008,7 +171099,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -149041,15 +171132,21 @@ fi Record Any Attempts to Run setsebool - At a minimum, the audit system should collect any execution attempt -of the setsebool command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -149084,11 +171181,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -149127,20 +171219,21 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - OL09-00-000660 - SV-271559r1092538_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + 0582 + OL09-00-000660 + SV-271559r1092538_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -149155,12 +171248,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/setsebool -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -149489,16 +171585,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/setsebool +- name: Record Any Attempts to Run setsebool - Perform remediation of Audit rules + for /usr/sbin/setsebool block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -149507,43 +171604,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setsebool -F perm=x @@ -149555,7 +171653,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -149565,12 +171663,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -149579,17 +171677,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset @@ -149601,7 +171700,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -149635,22 +171734,28 @@ fi Record Any Attempts to Run seunshare - At a minimum, the audit system should collect any execution attempt -of the seunshare command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-2(d) AU-12(c) AC-6(9) CM-6(a) + 0582 Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -149665,12 +171770,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/seunshare -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -149997,16 +172105,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/seunshare +- name: Record Any Attempts to Run seunshare - Perform remediation of Audit rules + for /usr/sbin/seunshare block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -150015,43 +172124,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/seunshare -F perm=x @@ -150063,7 +172173,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -150073,12 +172183,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -150087,17 +172197,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset @@ -150109,7 +172220,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -150146,14 +172257,14 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat,renameat2 -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat,renameat2 -F auid>=1000 -F auid!=unset -F key=delete Ensure auditd Collects File Deletion Events by User @@ -150161,19 +172272,19 @@ appropriate for your system: for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat,renameat2 -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename -S renameat -F auid>=1000 -F auid!=unset -F key=delete +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat2 -S renameat -F auid>=1000 -F auid!=unset -F key=delete This rule checks for multiple syscalls related to file deletion; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example: -audit_rules_file_deletion_events_rmdiraudit_rules_file_deletion_events_unlinkaudit_rules_file_deletion_events_unlinkat +audit_rules_file_deletion_events_rmdiraudit_rules_file_deletion_events_unlinkaudit_rules_file_deletion_events_unlinkataudit_rules_file_deletion_events_renameaudit_rules_file_deletion_events_renameataudit_rules_file_deletion_events_renameat2 1 11 @@ -150220,9 +172331,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000366 - CCI-000172 - CCI-002884 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -150301,9 +172409,9 @@ do ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" OTHER_FILTERS="" AUID_FILTERS="-F auid>=1000 -F auid!=unset" - SYSCALL="rmdir unlink unlinkat rename renameat" + SYSCALL="rmdir unlink unlinkat rename renameat renameat2" KEY="delete" - SYSCALL_GROUPING="rmdir unlink unlinkat rename renameat" + SYSCALL_GROUPING="rmdir unlink unlinkat rename renameat renameat2" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -150629,13 +172737,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rename -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rename -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -150682,11 +172790,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -150763,25 +172866,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -150800,7 +172903,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="rename" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -151134,7 +173237,7 @@ fi - restrict_strategy - name: Set architecture for audit rename tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -151163,7 +173266,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151171,10 +173274,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151183,43 +173287,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -151231,7 +173336,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151241,7 +173346,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151249,10 +173354,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151261,17 +173367,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -151283,7 +173390,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151316,7 +173423,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151324,10 +173431,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151336,43 +173444,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -151384,7 +173493,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151394,7 +173503,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151402,10 +173511,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151414,17 +173524,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -151436,7 +173547,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151479,13 +173590,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S renameat -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S renameat -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -151532,11 +173643,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -151613,25 +173719,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -151649,7 +173755,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="renameat" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -151983,7 +174089,7 @@ fi - restrict_strategy - name: Set architecture for audit renameat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -152011,7 +174117,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152019,10 +174125,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152031,43 +174138,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -152079,7 +174187,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152089,7 +174197,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152097,10 +174205,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152109,17 +174218,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -152131,7 +174241,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152163,7 +174273,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152171,10 +174281,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152183,43 +174294,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -152231,7 +174343,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152241,7 +174353,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152249,10 +174361,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152261,17 +174374,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -152283,7 +174397,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152325,13 +174439,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rmdir -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rmdir -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -152378,11 +174492,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -152459,25 +174568,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -152496,7 +174605,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="rmdir" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -152830,7 +174939,7 @@ fi - restrict_strategy - name: Set architecture for audit rmdir tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -152859,7 +174968,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -152867,10 +174976,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152879,43 +174989,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -152927,7 +175038,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152937,7 +175048,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -152945,10 +175056,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152957,17 +175069,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -152979,7 +175092,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153012,7 +175125,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -153020,10 +175133,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153032,43 +175146,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -153080,7 +175195,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153090,7 +175205,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -153098,10 +175213,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153110,17 +175226,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -153132,7 +175249,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153175,13 +175292,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlink -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlink -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -153228,11 +175345,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -153309,25 +175421,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -153346,7 +175458,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="unlink" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -153680,7 +175792,7 @@ fi - restrict_strategy - name: Set architecture for audit unlink tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -153709,7 +175821,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153717,10 +175829,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153729,43 +175842,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -153777,7 +175891,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153787,7 +175901,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153795,10 +175909,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153807,17 +175922,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -153829,7 +175945,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153862,7 +175978,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153870,10 +175986,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153882,43 +175999,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -153930,7 +176048,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153940,7 +176058,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153948,10 +176066,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153960,17 +176079,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -153982,7 +176102,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154025,13 +176145,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -154078,11 +176198,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -154159,25 +176274,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -154195,7 +176310,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="unlinkat" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -154529,7 +176644,7 @@ fi - restrict_strategy - name: Set architecture for audit unlinkat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -154557,7 +176672,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154565,10 +176680,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154577,43 +176693,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -154625,7 +176742,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154635,7 +176752,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154643,10 +176760,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154655,17 +176773,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -154677,7 +176796,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154709,7 +176828,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154717,10 +176836,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154729,43 +176849,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -154777,7 +176898,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154787,7 +176908,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154795,10 +176916,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154807,17 +176929,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -154829,7 +176952,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154956,8 +177079,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -154989,12 +177110,6 @@ separate rule for each syscall that needs to be checked. For example: SR 6.2 SR 7.1 SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 A.11.2.6 A.12.4.1 A.12.4.2 @@ -155754,11 +177869,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -155830,20 +177940,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. @@ -156506,7 +178618,7 @@ fi - restrict_strategy - name: Set architecture for audit creat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -156533,7 +178645,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156545,7 +178657,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156554,43 +178666,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156602,7 +178715,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156612,7 +178725,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156624,7 +178737,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156633,17 +178746,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156655,7 +178769,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156686,7 +178800,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156698,7 +178812,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156707,43 +178821,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156755,7 +178870,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156765,7 +178880,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156777,7 +178892,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156786,17 +178901,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156808,7 +178924,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156840,7 +178956,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156852,7 +178968,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156861,43 +178977,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -156909,7 +179026,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -156919,7 +179036,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156931,7 +179048,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156940,17 +179057,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -156962,7 +179080,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -156993,7 +179111,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -157005,7 +179123,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -157014,43 +179132,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -157062,7 +179181,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -157072,7 +179191,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -157084,7 +179203,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -157093,17 +179212,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -157115,7 +179235,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -157224,11 +179344,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -157300,20 +179415,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -157975,7 +180092,7 @@ fi - restrict_strategy - name: Set architecture for audit ftruncate tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -158001,7 +180118,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158013,7 +180130,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158022,43 +180139,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158070,7 +180188,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158080,7 +180198,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158092,7 +180210,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158101,17 +180219,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158123,7 +180242,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158153,7 +180272,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158165,7 +180284,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158174,43 +180293,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158222,7 +180342,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158232,7 +180352,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158244,7 +180364,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158253,17 +180373,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158275,7 +180396,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158306,7 +180427,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158318,7 +180439,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158327,43 +180448,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158375,7 +180497,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158385,7 +180507,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158397,7 +180519,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158406,17 +180528,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158428,7 +180551,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158458,7 +180581,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158470,7 +180593,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158479,43 +180602,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158527,7 +180651,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158537,7 +180661,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158549,7 +180673,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158558,17 +180682,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158580,7 +180705,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158688,11 +180813,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -158764,20 +180884,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. @@ -159440,7 +181562,7 @@ fi - restrict_strategy - name: Set architecture for audit open tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -159467,7 +181589,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159479,7 +181601,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159488,43 +181610,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159536,7 +181659,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159546,7 +181669,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159558,7 +181681,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159567,17 +181690,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159589,7 +181713,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159620,7 +181744,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159632,7 +181756,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159641,43 +181765,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159689,7 +181814,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159699,7 +181824,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159711,7 +181836,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159720,17 +181845,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159742,7 +181868,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159774,7 +181900,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159786,7 +181912,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159795,43 +181921,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -159843,7 +181970,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -159853,7 +181980,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159865,7 +181992,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159874,17 +182001,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -159896,7 +182024,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -159927,7 +182055,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159939,7 +182067,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159948,43 +182076,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -159996,7 +182125,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -160006,7 +182135,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -160018,7 +182147,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -160027,17 +182156,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -160049,7 +182179,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -160155,11 +182285,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -160231,18 +182356,20 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 - OL09-00-000635 - SV-271554r1092528_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -160904,7 +183031,7 @@ fi - restrict_strategy - name: Set architecture for audit open_by_handle_at tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -160931,7 +183058,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -160943,7 +183070,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -160952,43 +183079,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161000,7 +183128,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161010,7 +183138,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161022,7 +183150,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161031,17 +183159,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161053,7 +183182,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161084,7 +183213,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161096,7 +183225,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161105,43 +183234,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161153,7 +183283,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161163,7 +183293,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161175,7 +183305,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161184,17 +183314,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161206,7 +183337,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161237,7 +183368,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161249,7 +183380,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161258,43 +183389,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161306,7 +183438,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161316,7 +183448,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161328,7 +183460,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161337,17 +183469,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161359,7 +183492,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161389,7 +183522,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161401,7 +183534,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161410,43 +183543,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161458,7 +183592,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161468,7 +183602,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161480,7 +183614,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161489,17 +183623,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161511,7 +183646,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161619,11 +183754,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -161695,20 +183825,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -162370,7 +184502,7 @@ fi - restrict_strategy - name: Set architecture for audit openat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -162396,7 +184528,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162408,7 +184540,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162417,43 +184549,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162465,7 +184598,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162475,7 +184608,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162487,7 +184620,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162496,17 +184629,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162518,7 +184652,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162548,7 +184682,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162560,7 +184694,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162569,43 +184703,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162617,7 +184752,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162627,7 +184762,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162639,7 +184774,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162648,17 +184783,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162670,7 +184806,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162701,7 +184837,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162713,7 +184849,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162722,43 +184858,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162770,7 +184907,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -162780,7 +184917,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162792,7 +184929,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162801,17 +184938,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162823,7 +184961,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -162853,7 +184991,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162865,7 +185003,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162874,43 +185012,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162922,7 +185061,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -162932,7 +185071,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162944,7 +185083,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162953,17 +185092,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162975,7 +185115,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -163083,11 +185223,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -163159,20 +185294,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -163834,7 +185971,7 @@ fi - restrict_strategy - name: Set architecture for audit truncate tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -163860,7 +185997,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -163872,7 +186009,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -163881,43 +186018,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -163929,7 +186067,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -163939,7 +186077,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -163951,7 +186089,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -163960,17 +186098,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -163982,7 +186121,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -164012,7 +186151,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164024,7 +186163,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164033,43 +186172,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -164081,7 +186221,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -164091,7 +186231,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164103,7 +186243,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164112,17 +186252,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -164134,7 +186275,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -164165,7 +186306,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164177,7 +186318,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164186,43 +186327,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164234,7 +186376,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164244,7 +186386,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164256,7 +186398,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164265,17 +186407,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164287,7 +186430,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164317,7 +186460,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164329,7 +186472,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164338,43 +186481,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164386,7 +186530,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164396,7 +186540,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164408,7 +186552,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164417,17 +186561,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164439,7 +186584,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164547,7 +186692,6 @@ add the lines to file /etc/audit/audit.rules.MEA01.05 MEA02.01 3.1.7 - CCI-000172 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -164612,6 +186756,7 @@ add the lines to file /etc/audit/audit.rules.RS.AN-1 RS.AN-4 Req-10.2.7 + 0582 The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -164967,7 +187112,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -164993,7 +187138,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165004,7 +187149,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165013,43 +187158,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules - set_fact: audit_file="/etc/audit/rules.d/modules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -165061,7 +187207,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165071,7 +187217,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165082,7 +187228,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165091,17 +187237,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -165113,7 +187260,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165143,7 +187290,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165154,7 +187301,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165163,43 +187310,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules - set_fact: audit_file="/etc/audit/rules.d/modules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -165211,7 +187359,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165221,7 +187369,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165232,7 +187380,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165241,17 +187389,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -165263,7 +187412,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165299,7 +187448,8 @@ fi Ensure auditd Collects Information on Kernel Module Unloading - delete_module - To capture kernel module unloading events, use following line, setting ARCH to + +To capture kernel module loading and unloading events, use the following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S delete_module -F auid>=1000 -F auid!=unset -F key=modules @@ -165355,11 +187505,6 @@ add the line to file /etc/audit/audit.rules.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -165431,19 +187576,19 @@ add the line to file /etc/audit/audit.rules.RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000685 - SV-271564r1092548_rule + OL09-00-000685 + SV-271564r1092548_rule The removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -165467,7 +187612,7 @@ do SYSCALL="delete_module" KEY="modules" - SYSCALL_GROUPING="delete_module" + SYSCALL_GROUPING="create_module delete_module finit_module init_module query_module" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -165798,8 +187943,9 @@ fi - medium_severity - no_reboot_needed -- name: Set architecture for audit delete_module tasks - set_fact: +- name: Ensure auditd Collects Information on Kernel Module Unloading - delete_module + - Set architecture for audit ['delete_module'] tasks + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -165821,17 +187967,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for delete_module for 32bit platform +- name: Ensure auditd Collects Information on Kernel Module Unloading - delete_module + - Perform remediation of Audit rules for ['delete_module'] for 32bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165840,43 +187992,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -165888,23 +188041,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165913,17 +188071,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -165935,10 +188094,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -165961,17 +188120,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for delete_module for 64bit platform +- name: Ensure auditd Collects Information on Kernel Module Unloading - delete_module + - Perform remediation of Audit rules for ['delete_module'] for 64bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165980,43 +188145,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -166028,23 +188194,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166053,17 +188224,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -166075,10 +188247,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -166111,19 +188283,19 @@ fi Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - If the auditd daemon is configured to use the augenrules program -to read audit rules during daemon startup (the default), add the following lines to a file -with suffix .rules in the directory /etc/audit/rules.d to capture kernel module -loading and unloading events, setting ARCH to either b32 or b64 as appropriate for your system: + +To capture kernel module loading and unloading events, use the following line, setting ARCH to +either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S finit_module -F auid>=1000 -F auid!=unset -F key=modules - If the auditd daemon is configured to use the auditctl utility to read audit -rules during daemon startup, add the following lines to /etc/audit/audit.rules file -in order to capture kernel module loading and unloading events, setting ARCH to either b32 or -b64 as appropriate for your system: --a always,exit -F arch=ARCH -S finit_module -F auid>=1000 -F auid!=unset -F key=modules - + +Place to add the line depends on a way auditd daemon is configured. If it is configured +to use the augenrules program (the default), add the line to a file with suffix +.rules in the directory /etc/audit/rules.d. + +If the auditd daemon is configured to use the auditctl utility, +add the line to file /etc/audit/audit.rules. 1 11 12 @@ -166168,11 +188340,6 @@ b64 as appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -166244,19 +188411,19 @@ b64 as appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000690 - SV-271565r1092550_rule + OL09-00-000690 + SV-271565r1092550_rule The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -166280,7 +188447,7 @@ do SYSCALL="finit_module" KEY="modules" - SYSCALL_GROUPING="init_module finit_module" + SYSCALL_GROUPING="create_module delete_module finit_module init_module query_module" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -166611,8 +188778,9 @@ fi - medium_severity - no_reboot_needed -- name: Set architecture for audit finit_module tasks - set_fact: +- name: Ensure auditd Collects Information on Kernel Module Loading and Unloading + - finit_module - Set architecture for audit ['finit_module'] tasks + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -166634,19 +188802,24 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for finit_module for x86 platform +- name: Ensure auditd Collects Information on Kernel Module Loading and Unloading + - finit_module - Perform remediation of Audit rules for ['finit_module'] for 32bit + platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166655,43 +188828,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -166703,25 +188877,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166730,17 +188907,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -166752,10 +188930,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -166778,19 +188956,24 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for finit_module for x86_64 platform +- name: Ensure auditd Collects Information on Kernel Module Loading and Unloading + - finit_module - Perform remediation of Audit rules for ['finit_module'] for 64bit + platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166799,43 +188982,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -166847,25 +189031,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166874,17 +189061,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -166896,10 +189084,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -166932,7 +189120,8 @@ fi Ensure auditd Collects Information on Kernel Module Loading - init_module - To capture kernel module loading events, use following line, setting ARCH to + +To capture kernel module loading and unloading events, use the following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S init_module -F auid>=1000 -F auid!=unset -F key=modules @@ -166988,11 +189177,6 @@ add the line to file /etc/audit/audit.rules.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -167064,19 +189248,19 @@ add the line to file /etc/audit/audit.rules.RS.AN-1 RS.AN-4 Req-10.2.7 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000690 - SV-271565r1092550_rule + OL09-00-000690 + SV-271565r1092550_rule The addition of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -167100,7 +189284,7 @@ do SYSCALL="init_module" KEY="modules" - SYSCALL_GROUPING="init_module finit_module" + SYSCALL_GROUPING="create_module delete_module finit_module init_module query_module" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -167431,8 +189615,9 @@ fi - medium_severity - no_reboot_needed -- name: Set architecture for audit init_module tasks - set_fact: +- name: Ensure auditd Collects Information on Kernel Module Loading - init_module + - Set architecture for audit ['init_module'] tasks + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -167454,19 +189639,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for init_module for 32bit platform +- name: Ensure auditd Collects Information on Kernel Module Loading - init_module + - Perform remediation of Audit rules for ['init_module'] for 32bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167475,43 +189664,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -167523,25 +189713,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167550,17 +189743,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -167572,10 +189766,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -167598,19 +189792,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for init_module for 64bit platform +- name: Ensure auditd Collects Information on Kernel Module Loading - init_module + - Perform remediation of Audit rules for ['init_module'] for 64bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167619,43 +189817,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -167667,25 +189866,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167694,17 +189896,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -167716,10 +189919,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -167759,13 +189962,17 @@ and root. If the auditd daemon is configured to use the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d in order to watch for attempted manual edits of files involved in storing logon events: + -w /var/log/tallylog -p wa -k logins -w -p wa -k logins -w /var/log/lastlog -p wa -k logins + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: + -w /var/log/tallylog -p wa -k logins -w -p wa -k logins -w /var/log/lastlog -p wa -k logins @@ -167839,8 +190046,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -167938,7 +190143,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -167946,7 +190153,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -167962,12 +190171,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -167986,8 +190199,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/tallylog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168015,7 +190230,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168023,7 +190240,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168039,12 +190258,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168071,7 +190294,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168079,7 +190304,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168095,12 +190322,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -168119,8 +190350,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168148,7 +190381,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168156,7 +190391,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168172,12 +190409,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168204,7 +190445,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168212,7 +190455,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168228,12 +190473,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -168252,8 +190501,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/lastlog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168281,7 +190532,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168289,7 +190542,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168305,12 +190560,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168326,16 +190585,22 @@ fi Record Attempts to Alter Logon and Logout Events - faillock The audit system already collects login information for all users -and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing logon events: +and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w -p wa -k logins + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for unattempted manual -edits of files involved in storing logon events: +/etc/audit/audit.rules: + -w -p wa -k logins 1 @@ -168382,8 +190647,6 @@ edits of files involved in storing logon events: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -168455,18 +190718,19 @@ edits of files involved in storing logon events: RS.AN-1 RS.AN-4 Req-10.2.3 - SRG-OS-000392-GPOS-00172 - SRG-OS-000470-GPOS-00214 - SRG-OS-000473-GPOS-00218 - SRG-APP-000503-CTR-001275 - SRG-APP-000506-CTR-001290 + SRG-OS-000392-GPOS-00172 + SRG-OS-000470-GPOS-00214 + SRG-OS-000473-GPOS-00218 + SRG-APP-000503-CTR-001275 + SRG-APP-000506-CTR-001290 R73 A.3.SEC-OL1 + 0582 10.2.1.3 10.2.1 10.2 - OL09-00-000720 - SV-271571r1092560_rule + OL09-00-000720 + SV-271571r1092560_rule Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. # Remediation is applicable only in certain platforms @@ -168477,6 +190741,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne var_accounts_passwords_pam_faillock_dir='' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -168500,7 +190768,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168508,7 +190778,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168524,12 +190796,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -168548,8 +190824,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168577,7 +190855,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168585,7 +190865,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168601,12 +190883,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168614,7 +190900,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -168632,7 +190918,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy - name: XCCDF Value var_accounts_passwords_pam_faillock_dir # promote to variable set_fact: @@ -168640,9 +190926,9 @@ fi tags: - always -- name: Check if watch rule for {{ var_accounts_passwords_pam_faillock_dir }} already - exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Check if watch + rule for {{ var_accounts_passwords_pam_faillock_dir }} already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+{{ var_accounts_passwords_pam_faillock_dir }}\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -168665,11 +190951,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Search /etc/audit/rules.d + for other rules with specified key logins + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)logins$ patterns: '*.rules' @@ -168694,11 +190981,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Use /etc/audit/rules.d/logins.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/logins.rules when: @@ -168721,11 +191009,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -168748,11 +191037,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Add watch rule + for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w {{ var_accounts_passwords_pam_faillock_dir }} -p wa -k logins create: true @@ -168777,12 +191067,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for {{ var_accounts_passwords_pam_faillock_dir }} already - exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Check if watch + rule for {{ var_accounts_passwords_pam_faillock_dir }} already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+{{ var_accounts_passwords_pam_faillock_dir }}\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -168805,11 +191095,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Add watch rule + for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w {{ var_accounts_passwords_pam_faillock_dir }} -p wa -k logins state: present dest: /etc/audit/audit.rules @@ -168835,7 +191126,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -168849,16 +191140,22 @@ fi Record Attempts to Alter Logon and Logout Events - lastlog The audit system already collects login information for all users -and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing logon events: +and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /var/log/lastlog -p wa -k logins + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for unattempted manual -edits of files involved in storing logon events: +/etc/audit/audit.rules: + -w /var/log/lastlog -p wa -k logins 1 @@ -168905,11 +191202,6 @@ edits of files involved in storing logon events: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -168981,24 +191273,25 @@ edits of files involved in storing logon events: RS.AN-1 RS.AN-4 Req-10.2.3 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000473-GPOS-00218 - SRG-OS-000470-GPOS-00214 - SRG-APP-000495-CTR-001235 - SRG-APP-000503-CTR-001275 - SRG-APP-000506-CTR-001290 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000473-GPOS-00218 + SRG-OS-000470-GPOS-00214 + SRG-APP-000495-CTR-001235 + SRG-APP-000503-CTR-001275 + SRG-APP-000506-CTR-001290 R73 A.3.SEC-OL1 + 0582 10.2.1.3 10.2.1 10.2 - OL09-00-000700 - SV-271567r1092554_rule + OL09-00-000700 + SV-271567r1092554_rule Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. # Remediation is applicable only in certain platforms @@ -169007,6 +191300,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -169030,7 +191327,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169038,7 +191337,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169054,12 +191355,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -169078,8 +191383,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/lastlog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -169107,7 +191414,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169115,7 +191424,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169131,12 +191442,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -169144,7 +191459,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -169162,11 +191477,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/lastlog already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Check if watch + rule for /var/log/lastlog already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/lastlog\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -169189,11 +191505,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Search /etc/audit/rules.d + for other rules with specified key logins + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)logins$ patterns: '*.rules' @@ -169218,11 +191535,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Use /etc/audit/rules.d/logins.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/logins.rules when: @@ -169245,11 +191563,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -169272,11 +191591,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/lastlog in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Add watch rule + for /var/log/lastlog in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /var/log/lastlog -p wa -k logins create: true @@ -169301,11 +191621,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/lastlog already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Check if watch + rule for /var/log/lastlog already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/lastlog\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -169328,11 +191649,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/lastlog in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Add watch rule + for /var/log/lastlog in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /var/log/lastlog -p wa -k logins state: present dest: /etc/audit/audit.rules @@ -169358,7 +191680,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -169371,16 +191693,22 @@ fi Record Attempts to Alter Logon and Logout Events - tallylog The audit system already collects login information for all users -and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing logon events: +and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /var/log/tallylog -p wa -k logins + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for unattempted manual -edits of files involved in storing logon events: +/etc/audit/audit.rules: + -w /var/log/tallylog -p wa -k logins 1 @@ -169427,8 +191755,6 @@ edits of files involved in storing logon events: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -169500,15 +191826,16 @@ edits of files involved in storing logon events: RS.AN-1 RS.AN-4 Req-10.2.3 - SRG-OS-000392-GPOS-00172 - SRG-OS-000470-GPOS-00214 - SRG-OS-000473-GPOS-00218 - SRG-APP-000503-CTR-001275 + SRG-OS-000392-GPOS-00172 + SRG-OS-000470-GPOS-00214 + SRG-OS-000473-GPOS-00218 + SRG-APP-000503-CTR-001275 + 0582 10.2.1.3 10.2.1 10.2 - OL09-00-000725 - SV-271572r1092562_rule + OL09-00-000725 + SV-271572r1092562_rule Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. # Remediation is applicable only in certain platforms @@ -169517,6 +191844,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -169540,7 +191871,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169548,7 +191881,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169564,12 +191899,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -169588,8 +191927,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/tallylog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -169617,7 +191958,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169625,7 +191968,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169641,12 +191986,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -169654,7 +192003,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -169672,11 +192021,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/tallylog already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Check if watch + rule for /var/log/tallylog already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/tallylog\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -169699,11 +192049,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Search /etc/audit/rules.d + for other rules with specified key logins + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)logins$ patterns: '*.rules' @@ -169728,11 +192079,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Use /etc/audit/rules.d/logins.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/logins.rules when: @@ -169755,11 +192107,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -169782,11 +192135,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/tallylog in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Add watch rule + for /var/log/tallylog in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /var/log/tallylog -p wa -k logins create: true @@ -169811,11 +192165,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/tallylog already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Check if watch + rule for /var/log/tallylog already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/tallylog\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -169838,11 +192193,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/tallylog in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Add watch rule + for /var/log/tallylog in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /var/log/tallylog -p wa -k logins state: present dest: /etc/audit/audit.rules @@ -169868,7 +192224,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -169885,32 +192241,40 @@ fi privileged commands for all users and root. Ensure auditd Collects Information on the Use of Privileged Commands - init - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/init -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/init -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000730 - SV-271573r1092564_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000730 + SV-271573r1092564_rule Misuse of the init command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/init -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -170235,16 +192599,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/init +- name: Ensure auditd Collects Information on the Use of Privileged Commands - init + - Perform remediation of Audit rules for /usr/sbin/init block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170253,43 +192618,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/init -F perm=x -F @@ -170301,7 +192667,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170311,12 +192677,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170325,17 +192691,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset @@ -170347,7 +192714,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170377,32 +192744,40 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/poweroff -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/poweroff -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000735 - SV-271574r1092566_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000735 + SV-271574r1092566_rule Misuse of the poweroff command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/poweroff -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -170727,16 +193102,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/poweroff +- name: Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + - Perform remediation of Audit rules for /usr/sbin/poweroff block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170745,43 +193121,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/poweroff -F perm=x @@ -170793,7 +193170,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170803,12 +193180,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170817,17 +193194,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset @@ -170839,7 +193217,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170869,32 +193247,40 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - reboot - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/reboot -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/reboot -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000740 - SV-271575r1092568_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000740 + SV-271575r1092568_rule Misuse of the reboot command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/reboot -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -171219,16 +193605,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/reboot +- name: Ensure auditd Collects Information on the Use of Privileged Commands - reboot + - Perform remediation of Audit rules for /usr/sbin/reboot block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171237,43 +193624,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/reboot -F perm=x @@ -171285,7 +193673,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171295,12 +193683,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171309,17 +193697,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset @@ -171331,7 +193720,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171361,32 +193750,40 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/shutdown -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/shutdown -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000745 - SV-271576r1092570_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000745 + SV-271576r1092570_rule Misuse of the shutdown command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/shutdown -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -171711,16 +194108,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/shutdown +- name: Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + - Perform remediation of Audit rules for /usr/sbin/shutdown block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171729,43 +194127,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/shutdown -F perm=x @@ -171777,7 +194176,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171787,12 +194186,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171801,17 +194200,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset @@ -171823,7 +194223,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171864,8 +194264,9 @@ setuid / setgid programs using the following command: $ sudo find PARTITION -xdev -perm /6000 -type f 2>/dev/null For each setuid / setgid program identified by the previous command, an audit rule must be -present in the appropriate place using the following line structure: --a always,exit -F path=PROG_PATH -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged +present in the appropriate place using the following line structure, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -F path=PROG_PATH -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup, add the line to a file with suffix .rules in the @@ -171931,7 +194332,6 @@ file system during check or remediation caused undesirable errors.MEA01.05 MEA02.01 3.1.7 - CCI-002234 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -171966,12 +194366,6 @@ file system during check or remediation caused undesirable errors.SR 6.2 SR 7.1 SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 A.11.2.6 A.12.4.1 A.12.4.2 @@ -171993,14 +194387,14 @@ file system during check or remediation caused undesirable errors.A.6.1.3 A.6.2.1 A.6.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -172021,8 +194415,10 @@ file system during check or remediation caused undesirable errors.RS.AN-4 RS.CO-2 Req-10.2.2 - SRG-OS-000327-GPOS-00127 + SRG-OS-000327-GPOS-00127 R73 + 0582 + 0846 Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern that can have significant adverse impacts on organizations. @@ -172354,7 +194750,7 @@ function add_audit_rule() fi } -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then PRIV_CMDS=$(find / -perm /6000 -type f -not -path "/sysroot/*" 2>/dev/null) for PRIV_CMD in $PRIV_CMDS; do add_audit_rule $PRIV_CMD @@ -172548,18 +194944,23 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - at - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-2(d) AU-12(c) AC-6(9) @@ -172578,12 +194979,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/at -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -172910,16 +195314,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/at +- name: Ensure auditd Collects Information on the Use of Privileged Commands - at + - Perform remediation of Audit rules for /usr/bin/at block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -172928,43 +195333,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/at -F perm=x -F auid>=1000 @@ -172976,7 +195382,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -172986,12 +195392,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -173000,17 +195406,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset (?:-k @@ -173022,7 +195429,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -173054,15 +195461,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - chage - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -173097,11 +195510,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -173131,14 +195539,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -173149,19 +195557,19 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 - OL09-00-000550 - SV-271537r1092494_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + OL09-00-000550 + SV-271537r1092494_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -173176,12 +195584,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chage -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -173511,16 +195922,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chage +- name: Ensure auditd Collects Information on the Use of Privileged Commands - chage + - Perform remediation of Audit rules for /usr/bin/chage block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -173529,43 +195941,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chage -F perm=x -F @@ -173577,7 +195990,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -173587,12 +196000,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -173601,17 +196014,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset @@ -173623,7 +196037,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -173658,15 +196072,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - chsh - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -173701,11 +196121,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -173735,14 +196150,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -173753,15 +196168,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000565 - SV-271540r1092500_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000565 + SV-271540r1092500_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -173776,12 +196191,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chsh -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -174111,16 +196529,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chsh +- name: Ensure auditd Collects Information on the Use of Privileged Commands - chsh + - Perform remediation of Audit rules for /usr/bin/chsh block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174129,43 +196548,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chsh -F perm=x -F @@ -174177,7 +196597,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174187,12 +196607,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174201,17 +196621,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset @@ -174223,7 +196644,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174258,15 +196679,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - crontab - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -174301,11 +196728,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -174344,15 +196766,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000570 - SV-271541r1092502_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000570 + SV-271541r1092502_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -174367,12 +196789,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/crontab -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -174701,16 +197126,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/crontab +- name: Ensure auditd Collects Information on the Use of Privileged Commands - crontab + - Perform remediation of Audit rules for /usr/bin/crontab block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174719,43 +197145,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/crontab -F perm=x @@ -174767,7 +197194,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174777,12 +197204,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174791,17 +197218,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset @@ -174813,7 +197241,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174847,15 +197275,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -174890,11 +197324,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -174924,14 +197353,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -174942,16 +197371,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000575 - SV-271542r1092504_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000575 + SV-271542r1092504_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -174966,12 +197395,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/gpasswd -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -175301,16 +197733,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/gpasswd +- name: Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + - Perform remediation of Audit rules for /usr/bin/gpasswd block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175319,43 +197752,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/gpasswd -F perm=x @@ -175367,7 +197801,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175377,12 +197811,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175391,17 +197825,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset @@ -175413,7 +197848,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175448,41 +197883,42 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - kmod - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 AU-3 AU-3.1 AU-12(a) AU-12.1(ii) AU-12.1(iv)AU-12(c) MA-4(1)(a) - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000695 - SV-271566r1092552_rule + OL09-00-000695 + SV-271566r1092552_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -175493,12 +197929,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/kmod -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -175828,16 +198267,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/kmod +- name: Ensure auditd Collects Information on the Use of Privileged Commands - kmod + - Perform remediation of Audit rules for /usr/bin/kmod block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175846,43 +198286,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/kmod -F perm=x -F @@ -175894,7 +198335,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175904,12 +198345,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175918,17 +198359,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset @@ -175940,7 +198382,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175975,35 +198417,36 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - mount - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 AU-2(d) AU-12(c) AC-6(9) CM-6(a) - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - OL09-00-000630 - SV-271553r1092526_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + OL09-00-000630 + SV-271553r1092526_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -176018,12 +198461,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/mount -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -176351,16 +198797,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/mount +- name: Ensure auditd Collects Information on the Use of Privileged Commands - mount + - Perform remediation of Audit rules for /usr/bin/mount block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -176369,43 +198816,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/mount -F perm=x -F @@ -176417,7 +198865,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -176427,12 +198875,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -176441,17 +198889,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset @@ -176463,7 +198912,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -176496,15 +198945,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -176539,11 +198994,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -176573,14 +199023,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -176591,16 +199041,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000580 - SV-271543r1092506_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000580 + SV-271543r1092506_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -176615,12 +199065,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/newgrp -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -176950,16 +199403,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/newgrp +- name: Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + - Perform remediation of Audit rules for /usr/bin/newgrp block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -176968,43 +199422,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/newgrp -F perm=x -F @@ -177016,7 +199471,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177026,12 +199481,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -177040,17 +199495,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset @@ -177062,7 +199518,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177097,18 +199553,22 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/pam_timestamp_check --F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/pam_timestamp_check --F perm=x -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 12 @@ -177142,11 +199602,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -177185,16 +199640,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000585 - SV-271544r1092508_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000585 + SV-271544r1092508_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -177209,12 +199664,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/pam_timestamp_check -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -177543,16 +200001,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/pam_timestamp_check +- name: Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + - Perform remediation of Audit rules for /usr/sbin/pam_timestamp_check block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset @@ -177562,43 +200021,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/pam_timestamp_check @@ -177610,7 +200070,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177620,12 +200080,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset @@ -177635,17 +200095,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 @@ -177657,7 +200118,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177691,15 +200152,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - passwd - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -177734,11 +200201,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -177768,14 +200230,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -177786,16 +200248,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000590 - SV-271545r1092510_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000590 + SV-271545r1092510_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -177810,12 +200272,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/passwd -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -178145,16 +200610,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/passwd +- name: Ensure auditd Collects Information on the Use of Privileged Commands - passwd + - Perform remediation of Audit rules for /usr/bin/passwd block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178163,43 +200629,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/passwd -F perm=x -F @@ -178211,7 +200678,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178221,12 +200688,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178235,17 +200702,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset @@ -178257,7 +200725,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178292,15 +200760,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -178335,11 +200809,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -178378,15 +200847,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000595 - SV-271546r1092512_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000595 + SV-271546r1092512_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -178401,12 +200870,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/postdrop -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -178735,16 +201207,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/postdrop +- name: Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + - Perform remediation of Audit rules for /usr/sbin/postdrop block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178753,43 +201226,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postdrop -F perm=x @@ -178801,7 +201275,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178811,12 +201285,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178825,17 +201299,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset @@ -178847,7 +201322,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178881,15 +201356,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -178924,11 +201405,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -178967,15 +201443,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000600 - SV-271547r1092514_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000600 + SV-271547r1092514_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -178990,12 +201466,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/postqueue -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -179324,16 +201803,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/postqueue +- name: Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + - Perform remediation of Audit rules for /usr/sbin/postqueue block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179342,43 +201822,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postqueue -F perm=x @@ -179390,7 +201871,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179400,12 +201881,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179414,17 +201895,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset @@ -179436,7 +201918,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179470,31 +201952,32 @@ fi Record Any Attempts to Run ssh-agent - At a minimum, the audit system should collect any execution attempt -of the ssh-agent command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000605 - SV-271548r1092516_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000605 + SV-271548r1092516_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -179505,12 +201988,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/ssh-agent -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -179834,16 +202320,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/ssh-agent +- name: Record Any Attempts to Run ssh-agent - Perform remediation of Audit rules + for /usr/bin/ssh-agent block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179852,43 +202339,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/ssh-agent -F perm=x @@ -179900,7 +202388,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179910,12 +202398,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179924,17 +202412,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset @@ -179946,7 +202435,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179975,15 +202464,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -180018,11 +202513,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -180061,16 +202551,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000610 - SV-271549r1092518_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000610 + SV-271549r1092518_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -180085,12 +202575,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/libexec/openssh/ssh-keysign -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -180419,16 +202912,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/libexec/openssh/ssh-keysign +- name: Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + - Perform remediation of Audit rules for /usr/libexec/openssh/ssh-keysign block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset @@ -180438,43 +202932,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/libexec/openssh/ssh-keysign @@ -180486,7 +202981,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -180496,12 +202991,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset @@ -180511,17 +203006,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 @@ -180533,7 +203029,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -180567,15 +203063,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - su - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -180610,11 +203112,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -180653,20 +203150,20 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000064-GPOS-0003 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-OS-000755-GPOS-00220 - OL09-00-000540 - SV-271535r1092490_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000064-GPOS-00033 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-OS-000755-GPOS-00220 + OL09-00-000540 + SV-271535r1092490_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -180681,12 +203178,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/su -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -181015,16 +203515,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/su +- name: Ensure auditd Collects Information on the Use of Privileged Commands - su + - Perform remediation of Audit rules for /usr/bin/su block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181033,43 +203534,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/su -F perm=x -F auid>=1000 @@ -181081,7 +203583,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181091,12 +203593,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181105,17 +203607,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset (?:-k @@ -181127,7 +203630,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181161,15 +203664,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - sudo - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -181204,11 +203713,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -181247,20 +203751,20 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-OS-000755-GPOS-00220 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-OS-000755-GPOS-00220 R33 - OL09-00-000670 - SV-271561r1092542_rule + OL09-00-000670 + SV-271561r1092542_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -181275,12 +203779,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/sudo -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -181609,16 +204116,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/sudo +- name: Ensure auditd Collects Information on the Use of Privileged Commands - sudo + - Perform remediation of Audit rules for /usr/bin/sudo block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181627,43 +204135,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudo -F perm=x -F @@ -181675,7 +204184,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181685,12 +204194,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181699,17 +204208,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset @@ -181721,7 +204231,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181755,15 +204265,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -181798,11 +204314,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -181841,16 +204352,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - SRG-OS-000755-GPOS-00220 - OL09-00-000615 - SV-271550r1092520_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + SRG-OS-000755-GPOS-00220 + OL09-00-000615 + SV-271550r1092520_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -181865,12 +204376,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/sudoedit -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -182199,16 +204713,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/sudoedit +- name: Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + - Perform remediation of Audit rules for /usr/bin/sudoedit block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182217,43 +204732,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudoedit -F perm=x @@ -182265,7 +204781,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182275,12 +204791,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182289,17 +204805,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset @@ -182311,7 +204828,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182345,15 +204862,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - umount - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -182388,10 +204911,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -182430,15 +204949,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - OL09-00-000705 - SV-271568r1092556_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + OL09-00-000705 + SV-271568r1092556_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -182453,12 +204972,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/umount -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -182787,16 +205309,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/umount +- name: Ensure auditd Collects Information on the Use of Privileged Commands - umount + - Perform remediation of Audit rules for /usr/bin/umount block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182805,43 +205328,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/umount -F perm=x -F @@ -182853,7 +205377,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182863,12 +205387,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182877,17 +205401,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset @@ -182899,7 +205424,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182933,15 +205458,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -182976,11 +205507,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -183010,15 +205536,15 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R6.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R6.5 AC-2(4) AU-2(d) AU-3 @@ -183035,16 +205561,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000620 - SV-271551r1092522_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000620 + SV-271551r1092522_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -183059,12 +205585,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/unix_chkpwd -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -183400,16 +205929,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/unix_chkpwd +- name: Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + - Perform remediation of Audit rules for /usr/sbin/unix_chkpwd block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -183418,43 +205948,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_chkpwd -F perm=x @@ -183466,7 +205997,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -183476,12 +206007,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -183490,17 +206021,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset @@ -183512,7 +206044,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -183553,32 +206085,33 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000535 - SV-271534r1092488_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000064-GPOS-00033 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000535 + SV-271534r1092488_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -183593,12 +206126,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/unix_update -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -183922,16 +206458,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/unix_update +- name: Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + - Perform remediation of Audit rules for /usr/sbin/unix_update block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -183940,43 +206477,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_update -F perm=x @@ -183988,7 +206526,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -183998,12 +206536,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -184012,17 +206550,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset @@ -184034,7 +206573,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -184063,15 +206602,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -184106,11 +206651,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -184149,15 +206689,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000625 - SV-271552r1092524_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000625 + SV-271552r1092524_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -184172,12 +206712,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/userhelper -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -184506,16 +207049,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/userhelper +- name: Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + - Perform remediation of Audit rules for /usr/sbin/userhelper block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -184524,43 +207068,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/userhelper -F perm=x @@ -184572,7 +207117,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -184582,12 +207127,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -184596,17 +207141,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset @@ -184618,7 +207164,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -184652,33 +207198,34 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - usermod - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - OL09-00-000675 - SV-271562r1092544_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + OL09-00-000675 + SV-271562r1092544_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -184693,12 +207240,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/usermod -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -185022,16 +207572,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/usermod +- name: Ensure auditd Collects Information on the Use of Privileged Commands - usermod + - Perform remediation of Audit rules for /usr/sbin/usermod block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185040,43 +207591,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usermod -F perm=x @@ -185088,7 +207640,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185098,12 +207650,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185112,17 +207664,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset @@ -185134,7 +207687,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185163,26 +207716,31 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -185202,12 +207760,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/usernetctl -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -185535,16 +208096,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/usernetctl +- name: Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl + - Perform remediation of Audit rules for /usr/sbin/usernetctl block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185553,43 +208115,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usernetctl -F perm=x @@ -185601,7 +208164,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185611,12 +208174,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185625,17 +208188,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset @@ -185647,7 +208211,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185751,8 +208315,6 @@ not required. See an example of multiple combined syscalls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -185825,6 +208387,7 @@ not required. See an example of multiple combined syscalls: RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -186191,7 +208754,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -186219,7 +208782,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186228,7 +208791,7 @@ fi - stime - name: Check existence of adjtimex in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186237,43 +208800,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186284,7 +208848,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186293,7 +208857,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186302,7 +208866,7 @@ fi - stime - name: Check existence of adjtimex in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186311,17 +208875,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186332,7 +208897,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186363,7 +208928,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186371,7 +208936,7 @@ fi - settimeofday - name: Check existence of adjtimex in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186380,43 +208945,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186427,7 +208993,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186436,7 +209002,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186445,7 +209011,7 @@ fi - stime - name: Check existence of adjtimex in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186454,17 +209020,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186475,7 +209042,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186576,8 +209143,6 @@ desired, but is not required. See an example of multiple combined syscalls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -186650,6 +209215,7 @@ desired, but is not required. See an example of multiple combined syscalls: RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -187004,7 +209570,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -187032,13 +209598,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187047,43 +209613,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/time-change.rules - set_fact: audit_file="/etc/audit/rules.d/time-change.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/time-change.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187094,7 +209661,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187104,13 +209671,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187119,17 +209686,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187140,7 +209708,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187172,13 +209740,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187187,43 +209755,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/time-change.rules - set_fact: audit_file="/etc/audit/rules.d/time-change.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/time-change.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187234,7 +209803,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187244,13 +209813,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187259,17 +209828,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187280,7 +209850,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187382,8 +209952,6 @@ not required. See an example of multiple combined syscalls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -187455,6 +210023,7 @@ not required. See an example of multiple combined syscalls: RS.AN-1 RS.AN-4 Req-10.4.2.b + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -187849,7 +210418,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -187858,7 +210427,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -187867,43 +210436,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -187914,7 +210484,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -187923,7 +210493,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -187932,7 +210502,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -187941,17 +210511,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -187962,7 +210533,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -187993,7 +210564,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -188002,7 +210573,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188011,43 +210582,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188058,7 +210630,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188067,7 +210639,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -188076,7 +210648,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188085,17 +210657,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188106,7 +210679,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188211,8 +210784,6 @@ required. See an example of multiple combined system calls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -188285,6 +210856,7 @@ required. See an example of multiple combined system calls: RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -188655,7 +211227,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - stime syscall_grouping: @@ -188664,7 +211236,7 @@ fi - stime - name: Check existence of stime in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188673,43 +211245,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188720,7 +211293,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188729,7 +211302,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - stime syscall_grouping: @@ -188738,7 +211311,7 @@ fi - stime - name: Check existence of stime in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188747,17 +211320,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188768,7 +211342,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188806,18 +211380,23 @@ fi Record Attempts to Alter the localtime File - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /etc/localtime -p wa -k audit_time_rules + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /etc/localtime -p wa -k audit_time_rules -The -k option allows for the specification of a key in string form that can -be used for better reporting capability through ausearch and aureport and -should always be used. + 1 11 12 @@ -188863,8 +211442,6 @@ should always be used. MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -188937,6 +211514,7 @@ should always be used. RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -188947,6 +211525,12 @@ to the system time should be audited. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -188970,7 +211554,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/localtime" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -188978,7 +211564,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/localtime $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -188994,12 +211582,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/localtime$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/localtime -p wa -k audit_time_rules" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -189018,8 +211610,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_time_rules.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/localtime" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -189047,7 +211641,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/localtime" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -189055,7 +211651,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/localtime $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -189071,12 +211669,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/localtime$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/localtime -p wa -k audit_time_rules" >> "$audit_rules_file" + fi done @@ -189104,8 +211706,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/localtime already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter the localtime File - Check if watch rule for /etc/localtime + already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/localtime\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -189130,8 +211733,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_time_rules - find: +- name: Record Attempts to Alter the localtime File - Search /etc/audit/rules.d for + other rules with specified key audit_time_rules + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_time_rules$ patterns: '*.rules' @@ -189158,8 +211762,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_time_rules.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter the localtime File - Use /etc/audit/rules.d/audit_time_rules.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_time_rules.rules when: @@ -189184,8 +211789,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter the localtime File - Use matched file as the recipient + for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -189210,8 +211816,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/localtime in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter the localtime File - Add watch rule for /etc/localtime + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/localtime -p wa -k audit_time_rules create: true @@ -189238,8 +211845,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/localtime already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter the localtime File - Check if watch rule for /etc/localtime + already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/localtime\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -189264,8 +211872,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/localtime in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter the localtime File - Add watch rule for /etc/localtime + in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/localtime -p wa -k audit_time_rules state: present dest: /etc/audit/audit.rules @@ -189360,6 +211969,16 @@ normally. ignore single|halt single|halt + single|halt + + + The percentage remaining in disk space before prompting admin_space_left_action + The setting for admin_space_left as a percentage in /etc/audit/auditd.conf + 5 + 25 + 50 + 75 + 5 Action for auditd to take when disk errors @@ -189377,7 +211996,10 @@ for remediations the first value will be taken' syslog|single|halt syslog|single|halt syslog|single|halt + syslog|single|halt + syslog|single|halt syslog|single|halt + syslog|single|halt Action for auditd to take when disk is full @@ -189396,7 +212018,10 @@ for remediations the first value will be taken' syslog|single|halt syslog|single|halt halt|single + halt|single + halt|single halt|single + halt|single Auditd priority for flushing data to disk @@ -189465,6 +212090,7 @@ for remediations the first value will be taken' ignore email|exec|single|halt email|exec|single|halt + email|exec|single|halt The percentage remaining in disk space before prompting space_left_action @@ -189501,12 +212127,10 @@ following command: $ sudo df -h /var/log/audit/ /dev/sda2 24G 10.4G 13.6G 43% /var/log/audit - CCI-001849 - CCI-001851 - SRG-OS-000341-GPOS-00132 - SRG-OS-000342-GPOS-00133 - OL09-00-000850 - SV-271596r1091500_rule + SRG-OS-000341-GPOS-00132 + SRG-OS-000342-GPOS-00133 + OL09-00-000850 + SV-271596r1091500_rule Information stored in one location is vulnerable to accidental or incidental deletion or alteration. Off-loading is a common process in information systems with limited audit storage capacity. @@ -189549,7 +212173,6 @@ Restart the auditd service: DSS05.07 MEA02.01 3.3.1 - CCI-001851 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(B) 164.308(a)(5)(ii)(C) @@ -189591,12 +212214,12 @@ Restart the auditd service: RS.AN-1 RS.AN-4 Req-10.5.3 - SRG-OS-000479-GPOS-00224 - SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + SRG-OS-000342-GPOS-00133 10.3.3 10.3 - OL09-00-000855 - SV-271597r1092586_rule + OL09-00-000855 + SV-271597r1092586_rule The auditd service does not include the ability to send audit records to a centralized server for management directly. It does, however, include a plug-in for audit event multiplexor (audispd) to pass audit records @@ -189652,7 +212275,7 @@ fi - no_reboot_needed - name: Enable syslog plugin - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/plugins.d/syslog.conf regexp: ^active line: active = yes @@ -189728,7 +212351,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -189768,14 +212390,14 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 - SRG-APP-000098-CTR-000185 - SRG-APP-000099-CTR-000190 - SRG-APP-000100-CTR-000195 - SRG-APP-000100-CTR-000200 - SRG-APP-000109-CTR-000215 - SRG-APP-000290-CTR-000670 - SRG-APP-000357-CTR-000800 + SRG-OS-000047-GPOS-00023 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 Taking appropriate action in case of disk errors will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -189837,7 +212459,7 @@ fi - always - name: Configure auditd Disk Error Action on Disk Error - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_error_action = {{ var_auditd_disk_error_action.split('|')[0] }} regexp: ^\s*disk_error_action\s*=\s*.*$ @@ -189909,7 +212531,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -189949,9 +212570,9 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 - OL09-00-000760 - SV-271579r1091449_rule + SRG-OS-000047-GPOS-00023 + OL09-00-000760 + SV-271579r1091449_rule Taking appropriate action in case of disk errors will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -190007,7 +212628,7 @@ fi - always - name: Configure auditd Disk Error Action on Disk Error - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_error_action = {{ var_auditd_disk_error_action }} regexp: ^\s*disk_error_action\s*=\s*.*$ @@ -190082,7 +212703,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -190122,7 +212742,7 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 + SRG-OS-000047-GPOS-00023 Taking appropriate action in case of a filled audit storage volume will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -190179,7 +212799,7 @@ fi - always - name: Configure auditd Disk Full Action when Disk Space Is Full - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_full_action = {{ var_auditd_disk_full_action.split('|')[0] }} regexp: ^\s*disk_full_action\s*=\s*.*$ @@ -190251,7 +212871,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -190291,9 +212910,9 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 - OL09-00-000765 - SV-271580r1091452_rule + SRG-OS-000047-GPOS-00023 + OL09-00-000765 + SV-271580r1091452_rule Taking appropriate action in case of a filled audit storage volume will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -190349,7 +212968,7 @@ fi - always - name: Configure auditd Disk Full Action when Disk Space Is Full - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_full_action = {{ var_auditd_disk_full_action }} regexp: ^\s*disk_full_action\s*=\s*.*$ @@ -190418,8 +213037,6 @@ via email for those situations: DSS05.07 MEA02.01 3.3.1 - CCI-001855 - CCI-000139 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -190449,21 +213066,21 @@ via email for those situations: A.16.1.5 A.16.1.7 A.17.2.1 - CIP-003-8 R1.3 - CIP-003-8 R3 - CIP-003-8 R3.1 - CIP-003-8 R3.2 - CIP-003-8 R3.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R1.3 + CIP-003-8 R3 + CIP-003-8 R3.1 + CIP-003-8 R3.2 + CIP-003-8 R3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-5(1) AU-5(a) AU-5(2) @@ -190475,10 +213092,10 @@ via email for those situations: RS.AN-1 RS.AN-4 Req-10.7.a - SRG-OS-000046-GPOS-00022 - SRG-OS-000343-GPOS-00134 - OL09-00-000825 - SV-271591r1092578_rule + SRG-OS-000046-GPOS-00022 + SRG-OS-000343-GPOS-00134 + OL09-00-000825 + SV-271591r1092578_rule Email sent to the root account is typically aliased to the administrators of the system, who can take appropriate action. # Remediation is applicable only in certain platforms @@ -190537,9 +213154,11 @@ fi tags: - always -- name: Configure auditd mail_acct Action on Low Disk Space - lineinfile: +- name: Configure auditd mail_acct Action on Low Disk Space - Configure auditd mail_acct + Action on Low Disk Space + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf + regexp: ^action_mail_acct line: action_mail_acct = {{ var_auditd_action_mail_acct }} state: present create: true @@ -190614,7 +213233,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.07 MEA02.01 3.3.1 - CCI-001855 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -190656,13 +213274,11 @@ determined. Details regarding all possible values for ACTION ar RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 + SRG-OS-000343-GPOS-00134 10.5.1 10.5 - OL09-00-000875 - OL09-00-000885 - SV-271601r1091515_rule - SV-271603r1092592_rule + OL09-00-000885 + SV-271603r1092592_rule Administrators should be made aware of an inability to record audit records. If a separate partition or logical volume of adequate size is used, running low on space for audit records should never occur. @@ -190705,7 +213321,6 @@ fi manager: auto tags: - CJIS-5.4.1.1 - - DISA-STIG-OL09-00-000875 - DISA-STIG-OL09-00-000885 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) @@ -190729,7 +213344,7 @@ fi - always - name: Configure auditd admin_space_left Action on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: admin_space_left_action = {{ var_auditd_admin_space_left_action .split('|')[0] }} @@ -190741,7 +213356,6 @@ fi - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - - DISA-STIG-OL09-00-000875 - DISA-STIG-OL09-00-000885 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) @@ -190767,6 +213381,158 @@ fi + + Configure auditd admin_space_left on Low Disk Space + The auditd service can be configured to take an action +when disk space is running low but prior to running out of space completely. +Edit the file /etc/audit/auditd.conf. Add or modify the following line, +substituting PERCENTAGE appropriately: +admin_space_left = PERCENTAGE% +Set this value to +to cause the system to perform an action. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 4.3.4.4.7 + 4.3.4.5.6 + 4.3.4.5.7 + 4.3.4.5.8 + 4.4.2.1 + 4.4.2.2 + 4.4.2.4 + SR 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + SR 7.1 + SR 7.2 + A.12.1.3 + A.12.4.1 + A.12.4.2 + A.12.4.3 + A.12.4.4 + A.12.7.1 + A.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000343-GPOS-00134 + OL09-00-000875 + SV-271601r1091515_rule + Notifying administrators of an impending disk space problem may allow them to +take corrective action prior to any disruption. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_auditd_admin_space_left_percentage='' + + +grep -q "^admin_space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \ + sed -i "s/^admin_space_left[[:space:]]*=.*$/admin_space_left = $var_auditd_admin_space_left_percentage%/g" /etc/audit/auditd.conf || \ + echo "admin_space_left = $var_auditd_admin_space_left_percentage%" >> /etc/audit/auditd.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000875 + - NIST-800-53-AU-5(1) + - NIST-800-53-AU-5(2) + - NIST-800-53-AU-5(4) + - NIST-800-53-AU-5(b) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - auditd_data_retention_admin_space_left_percentage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_auditd_admin_space_left_percentage # promote to variable + set_fact: + var_auditd_admin_space_left_percentage: !!str + tags: + - always + +- name: Configure auditd admin_space_left on Low Disk Space + ansible.builtin.lineinfile: + dest: /etc/audit/auditd.conf + line: admin_space_left = {{ var_auditd_admin_space_left_percentage }}% + regexp: ^\s*admin_space_left\s*=\s*.*$ + state: present + create: true + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000875 + - NIST-800-53-AU-5(1) + - NIST-800-53-AU-5(2) + - NIST-800-53-AU-5(4) + - NIST-800-53-AU-5(b) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - auditd_data_retention_admin_space_left_percentage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + Configure auditd flush priority The auditd service can be configured to @@ -190808,7 +213574,6 @@ fully synchronized with the log files on the disk: MEA01.05 MEA02.01 3.3.1 - CCI-001576 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -190838,13 +213603,13 @@ fully synchronized with the log files on the disk: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 + CIP-004-6 R2.2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 AU-11 CM-6(a) DE.CM-1 @@ -190853,7 +213618,8 @@ fully synchronized with the log files on the disk: ID.SC-4 PR.PT-1 FAU_GEN.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 0582 Audit data should be synchronously written to disk to ensure log integrity. These parameters assure that all audit event data is fully synchronized with the log files on the disk. @@ -190914,7 +213680,7 @@ fi - always - name: Configure auditd Flush Priority - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf regexp: ^\s*flush\s*=\s*.*$ line: flush = {{ var_auditd_flush }} @@ -190983,7 +213749,6 @@ The setting is case-insensitive. DSS05.04 DSS05.07 MEA02.01 - CCI-000140 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -191025,7 +213790,7 @@ The setting is case-insensitive. RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000047-GPOS-00023 + SRG-OS-000047-GPOS-00023 A.3.SEC-OL6 Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by @@ -191088,7 +213853,7 @@ fi - always - name: Configure auditd max_log_file_action Upon Reaching Maximum Log Size - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: max_log_file_action = {{ var_auditd_max_log_file_action }} regexp: ^\s*max_log_file_action\s*=\s*.*$ @@ -191160,7 +213925,6 @@ occurs. This is the default. The setting is case-insensitive.DSS05.04 DSS05.07 MEA02.01 - CCI-000140 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -191202,16 +213966,16 @@ occurs. This is the default. The setting is case-insensitive.RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000047-GPOS-00023 - SRG-APP-000098-CTR-000185 - SRG-APP-000099-CTR-000190 - SRG-APP-000100-CTR-000195 - SRG-APP-000100-CTR-000200 - SRG-APP-000109-CTR-000215 - SRG-APP-000290-CTR-000670 - SRG-APP-000357-CTR-000800 - OL09-00-000770 - SV-271581r1091455_rule + SRG-OS-000047-GPOS-00023 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + OL09-00-000770 + SV-271581r1091455_rule Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by being overwhelmed with log data. However, for systems that must never discard @@ -191271,7 +214035,7 @@ fi - always - name: Configure auditd max_log_file_action Upon Reaching Maximum Log Size - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: max_log_file_action = {{ var_auditd_max_log_file_action }} regexp: ^\s*max_log_file_action\s*=\s*.*$ @@ -191340,7 +214104,6 @@ notify the user of an issue. DSS05.04 DSS05.07 MEA02.01 - CCI-001855 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -191381,7 +214144,7 @@ notify the user of an issue. RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 + SRG-OS-000343-GPOS-00134 10.5.1 10.5 Notifying administrators of an impending disk space problem may allow them to @@ -191425,7 +214188,7 @@ fi - always - name: Configure auditd space_left on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: space_left = {{ var_auditd_space_left }} regexp: ^\s*space_left\s*=\s*.*$ @@ -191502,7 +214265,6 @@ also include suspend, single, and DSS05.07 MEA02.01 3.3.1 - CCI-001855 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -191544,11 +214306,11 @@ also include suspend, single, and RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 + SRG-OS-000343-GPOS-00134 10.5.1 10.5 - OL09-00-000870 - SV-271600r1091512_rule + OL09-00-000870 + SV-271600r1134858_rule Notifying administrators of an impending disk space problem may allow them to take corrective action prior to any disruption. # Remediation is applicable only in certain platforms @@ -191618,7 +214380,7 @@ fi - always - name: Configure auditd space_left Action on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: space_left_action = {{ var_auditd_space_left_action.split('|')[0] }} regexp: ^\s*space_left_action\s*=\s*.*$ @@ -191691,7 +214453,6 @@ notify the user of an issue. DSS05.04 DSS05.07 MEA02.01 - CCI-001855 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -191732,9 +214493,9 @@ notify the user of an issue. RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 - OL09-00-000865 - SV-271599r1091509_rule + SRG-OS-000343-GPOS-00134 + OL09-00-000865 + SV-271599r1134856_rule Notifying administrators of an impending disk space problem may allow them to take corrective action prior to any disruption. # Remediation is applicable only in certain platforms @@ -191775,7 +214536,7 @@ fi - always - name: Configure auditd space_left on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: space_left = {{ var_auditd_space_left_percentage }}% regexp: ^\s*space_left\s*=\s*.*$ @@ -191812,18 +214573,22 @@ fi To configure Audit daemon to issue an explicit flush to disk command after writing records, set freq to in /etc/audit/auditd.conf. - CCI-000154 CM-6 FAU_GEN.1 - SRG-OS-000051-GPOS-00024 - OL09-00-000775 - SV-271582r1092574_rule + SRG-OS-000051-GPOS-00024 + 0582 + OL09-00-000775 + SV-271582r1092574_rule If option freq isn't set to , the flush to disk may happen after higher number of records, increasing the danger of audit loss. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +var_auditd_freq='' + + + if [ -e "/etc/audit/auditd.conf" ] ; then LC_ALL=C sed -i "/^\s*freq\s*=\s*/Id" "/etc/audit/auditd.conf" @@ -191835,7 +214600,7 @@ sed -i -e '$a\' "/etc/audit/auditd.conf" cp "/etc/audit/auditd.conf" "/etc/audit/auditd.conf.bak" # Insert at the end of the file -printf '%s\n' "freq = 50" >> "/etc/audit/auditd.conf" +printf '%s\n' "freq = $var_auditd_freq" >> "/etc/audit/auditd.conf" # Clean up after ourselves. rm "/etc/audit/auditd.conf.bak" @@ -191855,12 +214620,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy +- name: XCCDF Value var_auditd_freq # promote to variable + set_fact: + var_auditd_freq: !!str + tags: + - always - name: Set number of records to cause an explicit flush to audit logs block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*freq\s*=\s* @@ -191870,7 +214640,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*freq\s*=\s* @@ -191878,11 +214648,11 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*freq\s*=\s* - line: freq = 50 + line: freq = {{ var_auditd_freq }} state: present when: - '"audit" in ansible_facts.packages' @@ -191898,6 +214668,7 @@ fi - restrict_strategy + @@ -191909,13 +214680,12 @@ fi To configure Audit daemon to include local events in Audit logs, set local_events to yes in /etc/audit/auditd.conf. This is the default setting. - CCI-000366 - CCI-000169 CM-6 - SRG-OS-000062-GPOS-00031 - SRG-OS-000480-GPOS-00227 - OL09-00-000800 - SV-271586r1092576_rule + SRG-OS-000062-GPOS-00031 + SRG-OS-000480-GPOS-00227 + 0582 + OL09-00-000800 + SV-271586r1092576_rule If option local_events isn't set to yes only events from network will be aggregated. # Remediation is applicable only in certain platforms @@ -191957,7 +214727,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*local_events\s*=\s* @@ -191967,7 +214737,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*local_events\s*=\s* @@ -191975,7 +214745,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*local_events\s*=\s* @@ -192007,24 +214777,23 @@ fi architecture, and socket address information before writing the events to disk, set log_format to ENRICHED in /etc/audit/auditd.conf. - CCI-000366 - CCI-001487 CM-6 AU-3 FAU_GEN.1.2 - SRG-OS-000255-GPOS-00096 - SRG-OS-000480-GPOS-00227 - SRG-APP-000096-CTR-000175 - SRG-APP-000097-CTR-000180 - SRG-APP-000098-CTR-000185 - SRG-APP-000099-CTR-000190 - SRG-APP-000100-CTR-000195 - SRG-APP-000100-CTR-000200 - SRG-APP-000109-CTR-000215 - SRG-APP-000290-CTR-000670 - SRG-APP-000357-CTR-000800 - OL09-00-000835 - SV-271593r1092580_rule + SRG-OS-000255-GPOS-00096 + SRG-OS-000480-GPOS-00227 + SRG-APP-000096-CTR-000175 + SRG-APP-000097-CTR-000180 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + 0582 + OL09-00-000835 + SV-271593r1092580_rule If option log_format isn't set to ENRICHED, the audit records will be stored in a format exactly as the kernel sends them. # Remediation is applicable only in certain platforms @@ -192067,7 +214836,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*log_format\s*=\s* @@ -192077,7 +214846,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*log_format\s*=\s* @@ -192085,7 +214854,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*log_format\s*=\s* @@ -192120,18 +214889,17 @@ set name_format to Whenever the variable var_auditd_name_format uses a multiple value option, for example A|B|C, the first value will be used when remediating this rule. - CCI-000132 - CCI-001851 CM-6 AU-3 FAU_GEN.1.2 - SRG-OS-000039-GPOS-00017 - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 + SRG-OS-000039-GPOS-00017 + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + 0582 10.2.2 10.2 - OL09-00-000755 - SV-271578r1092572_rule + OL09-00-000755 + SV-271578r1092572_rule If option name_format is left at its default value of none, audit events from different computers may be hard to distinguish. @@ -192207,7 +214975,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*name_format\s*=\s* @@ -192217,7 +214985,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*name_format\s*=\s* @@ -192225,7 +214993,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*name_format\s*=\s* @@ -192260,12 +215028,11 @@ fi The audit system should have an action setup in the event the internal event queue becomes full. To setup an overflow action edit /etc/audit/auditd.conf. Set overflow_action to one of the following values: syslog, single, halt. - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-000860 - SV-271598r1092588_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-000860 + SV-271598r1092588_rule The audit system should have an action setup in the event the internal event queue becomes full so that no data is lost. # Remediation is applicable only in certain platforms @@ -192307,7 +215074,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*overflow_action\s*=\s* @@ -192317,7 +215084,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*overflow_action\s*=\s* @@ -192325,7 +215092,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*overflow_action\s*=\s* @@ -192356,11 +215123,11 @@ fi To configure Audit daemon to write Audit logs to the disk, set write_logs to yes in /etc/audit/auditd.conf. This is the default setting. - CCI-000366 CM-6 - SRG-OS-000480-GPOS-00227 - OL09-00-000880 - SV-271602r1092590_rule + SRG-OS-000480-GPOS-00227 + 0582 + OL09-00-000880 + SV-271602r1092590_rule If write_logs isn't set to yes, the Audit logs will not be written to the disk. # Remediation is applicable only in certain platforms @@ -192402,7 +215169,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*write_logs\s*=\s* @@ -192412,7 +215179,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*write_logs\s*=\s* @@ -192420,7 +215187,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*write_logs\s*=\s* @@ -192458,11 +215225,10 @@ deals with permissions of auditd related files. To properly set the permissions of /etc/audit/auditd.conf, run the command: $ sudo chmod 0640 /etc/audit/auditd.conf - CCI-000171 AU-12(b) - SRG-OS-000063-GPOS-00032 - OL09-00-000810 - SV-271588r1091476_rule + SRG-OS-000063-GPOS-00032 + OL09-00-000810 + SV-271588r1091476_rule Without the capability to restrict the roles and individuals that can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming @@ -192492,7 +215258,7 @@ fi - no_reboot_needed - name: Test for existence /etc/audit/auditd.conf - stat: + ansible.builtin.stat: path: /etc/audit/auditd.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -192507,7 +215273,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/audit/auditd.conf - file: + ansible.builtin.file: path: /etc/audit/auditd.conf mode: u-xs,g-xws,o-xwrt when: @@ -192536,11 +215302,10 @@ fi To properly set the permissions of /etc/audit/rules.d/*.rules, run the command: $ sudo chmod 0600 /etc/audit/rules.d/*.rules - CCI-000171 AU-12(b) - SRG-OS-000063-GPOS-00032 - OL09-00-000805 - SV-271587r1091473_rule + SRG-OS-000063-GPOS-00032 + OL09-00-000805 + SV-271587r1091473_rule Without the capability to restrict the roles and individuals that can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming @@ -192550,7 +215315,7 @@ those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*rules$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; +find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*rules$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -192570,7 +215335,7 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) - command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex "^.*rules$" register: files_found changed_when: false @@ -192588,7 +215353,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/audit/rules.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xwrs,o-xwrt state: file @@ -192633,27 +215398,23 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + 0582 + 0846 Unsuccessful attempts to access a file might be signs of malicious activity happening within the system. Auditing of such activities helps in their monitoring and investigation. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -192688,7 +215449,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules content: | ## Unsuccessful file access (any other opens) This has to go last. @@ -192712,6 +215473,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -192742,21 +215504,17 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + 0582 + 0846 Auditing of successful attempts to access a file helps in investigation of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -192790,7 +215548,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules content: | ## Successful file access (any other opens) This has to go last. @@ -192813,6 +215571,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -192855,8 +215614,8 @@ Load new Audit rules into kernel by running: It might happen that Audit buffer configured by this rule is not large enough for certain use cases. If that is the case, the buffer size can be overridden by placing -b larger_buffer_size into a file within /etc/audit/rules.d directory, replacing larger_file_size with the desired value. The file name should start with a number higher than 10 and lower than 99. AU-2(a) FAU_GEN.1 - SRG-OS-000365-GPOS-00152 - SRG-OS-000475-GPOS-00220 + SRG-OS-000365-GPOS-00152 + SRG-OS-000475-GPOS-00220 Without basic configurations, audit may not perform as expected. It may not be able to correctly handle events under stressful conditions, or log events in case of failure. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -192898,7 +215657,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/10-base-config.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/10-base-config.rules content: |+ ## First rule - delete all @@ -192930,6 +215689,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/10-base-config.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -192969,21 +215729,21 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 Unsuccessful file creations might be a sign of a malicious action being performed on the system. Keeping log of such events helps in monitoring and investigation of such actions. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193026,7 +215786,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules content: | ## Unsuccessful file creation (open with O_CREAT) @@ -193058,6 +215818,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193091,15 +215852,15 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 Auditing of successful attempts to create a file helps in investigation of actions which happened on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193136,7 +215897,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules content: | ## Successful file creation (open with O_CREAT) @@ -193162,6 +215923,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193193,18 +215955,18 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-OS-000468-GPOS-00212 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 Unsuccessful attempts to delete a file might be signs of malicious activities. Auditing of such events help in monitoring and investigating of such activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193239,7 +216001,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules content: | ## Unsuccessful file delete @@ -193263,6 +216025,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193292,16 +216055,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-OS-000468-GPOS-00212 Auditing of successful attempts to delete a file may help in monitoring and investigation of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193334,7 +216097,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules content: | ## Successful file delete @@ -193356,6 +216119,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193386,18 +216150,15 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load - CCI-000162 - CCI-000163 - CCI-000164 AU-2(a) FAU_GEN.1.2 - SRG-OS-000462-GPOS-00206 - SRG-OS-000475-GPOS-00220 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000121-CTR-000255 - SRG-APP-000495-CTR-001235 + SRG-OS-000462-GPOS-00206 + SRG-OS-000475-GPOS-00220 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000121-CTR-000255 + SRG-APP-000495-CTR-001235 If modification of login UIDs is not prevented, they can be changed by unprivileged users and make auditing complicated or impossible. # Remediation is applicable only in certain platforms @@ -193430,7 +216191,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/11-loginuid.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/11-loginuid.rules content: |+ ## Make the loginuid immutable. This prevents tampering with the auid. @@ -193452,6 +216213,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/11-loginuid.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193491,21 +216253,21 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 Unsuccessful file modifications might be a sign of a malicious action being performed on the system. Auditing of such events helps in detection and investigation of such actions. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193548,7 +216310,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules content: | ## Unsuccessful file modifications (open for write or truncate) @@ -193580,6 +216342,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193613,15 +216376,15 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 Auditing of successful attempts to modify a file helps in investigation of actions which happened on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193658,7 +216421,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules content: | ## Successful file modifications (open for write or truncate) @@ -193684,6 +216447,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193718,9 +216482,9 @@ Load new Audit rules into kernel by running: AU-2(a) FAU_GEN.1.1.c - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-OS-000475-GPOS-00220 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-OS-000475-GPOS-00220 Loading of a malicious kernel module introduces a risk to the system, as the module has access to sensitive data and perform actions at the operating system kernel level. Having such events audited helps in monitoring and investigating of malicious activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193755,7 +216519,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/43-module-load.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/43-module-load.rules content: | ## These rules watch for kernel module insertion. By monitoring @@ -193780,6 +216544,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/43-module-load.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193817,6 +216582,9 @@ The following rules configure audit as described above: ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -193921,19 +216689,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000004-GPOS-00004 - SRG-OS-000241-GPOS-00091 - SRG-OS-000476-GPOS-00221 - SRG-OS-000327-GPOS-00127 - SRG-OS-000475-GPOS-00220 - SRG-OS-000239-GPOS-00089 - SRG-OS-000274-GPOS-00104 - SRG-OS-000275-GPOS-00105 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 + SRG-OS-000004-GPOS-00004 + SRG-OS-000241-GPOS-00091 + SRG-OS-000476-GPOS-00221 + SRG-OS-000327-GPOS-00127 + SRG-OS-000475-GPOS-00220 + SRG-OS-000239-GPOS-00089 + SRG-OS-000274-GPOS-00104 + SRG-OS-000275-GPOS-00105 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 Auditing of events listed in the description provides data for monitoring and investigation of potentially malicious events e.g. tampering with Audit logs, malicious access to files storing information about system users and groups etc. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193952,6 +216720,9 @@ cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42.rules ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -194076,7 +216847,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/30-ospp-v42.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42.rules content: |+ ## The purpose of these rules is to meet the requirements for Operating @@ -194092,6 +216863,9 @@ fi ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules + ## + ## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -194209,6 +216983,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194240,16 +217015,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 Unsuccessful attempts to change an ownership of files or directories might be signs of a malicious activity. Having such events audited helps in monitoring and investigation of such activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194284,7 +217059,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules content: | ## Unsuccessful ownership change @@ -194308,6 +217083,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194337,17 +217113,17 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - Auditing of successful ownership changes of files or directories helps in monitoring or investingating of activities performed on the system. + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + Auditing of successful ownership changes of files or directories helps in monitoring or investigating of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194379,7 +217155,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules content: | ## Successful ownership change @@ -194401,6 +217177,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194432,16 +217209,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 Unsuccessful attempts to change permissions of files or directories might be signs of malicious activity. Having such events audited helps in monitoring and investigation of such activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194476,7 +217253,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules content: | ## Unsuccessful permission change @@ -194500,6 +217277,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194529,16 +217307,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 Auditing successful file or directory permission changes helps in monitoring and investigating of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194571,7 +217349,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules content: | ## Successful permission change @@ -194593,6 +217371,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194614,13 +217393,13 @@ fi - + OVALFileLinker from SCAP Security Guide - ssg: [0, 1, 76], python: 3.9.21 + ssg: [0, 1, 79], python: 3.9.23 5.11 - 2025-05-06T00:00:00 + 2025-12-16T00:00:00 @@ -194683,27 +217462,6 @@ fi - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - - Oracle Linux 9 - - - Audit rules that detect changes to the system's - mandatory access controls (SELinux) in usr/share/selinux are enabled. - - - - - - - - - - - - Record Events that Modify the System's Network Environment @@ -194717,88 +217475,24 @@ fi - - - - + + + + - - - - + + + + - - - Record Attempts to Alter Process and Session Initiation Information - - Oracle Linux 9 - - - Audit rules should capture information about session initiation. - - - - - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - - Oracle Linux 9 - - - Audit actions taken by system administrators on the system - /etc/sudoers. - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - - Oracle Linux 9 - - - Audit actions taken by system administrators on the system - /etc/sudoers.d/. - - - - - - - - - - - - Record Events When Privileged Executables Are Run @@ -194834,17 +217528,9 @@ fi Audit actions taken by system administrators on the system. - - - - - - - - - - - + + + @@ -194907,11 +217593,19 @@ fi - + + + + + - + + + + + @@ -194971,16 +217665,11 @@ fi - - - - - - - - + + + @@ -195086,6 +217775,7 @@ fi + @@ -195121,90 +217811,6 @@ fi - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - - Oracle Linux 9 - - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - - Oracle Linux 9 - - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - - Oracle Linux 9 - - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events @@ -195374,26 +217980,6 @@ fi - - - Record Attempts to Alter the localtime File - - Oracle Linux 9 - - - Record attempts to alter time through /etc/localtime. - - - - - - - - - - - - Configure auditd to use audispd's syslog plugin @@ -195489,6 +218075,19 @@ fi + + + Configure auditd admin_space_left on Low Disk Space + + Oracle Linux 9 + + + admin_space_left setting in /etc/audit/auditd.conf is set to at least a certain value + + + + + Configure auditd flush priority @@ -195769,7 +218368,7 @@ fi Ensure that no other user than chrony is configured to run the chrony service - + @@ -195811,11 +218410,17 @@ fi - + + + + - + + + + @@ -195874,18 +218479,24 @@ fi - + - Ensure tftp Daemon Uses Secure Mode + Ensure tftp systemd Service Uses Secure Mode Oracle Linux 9 - + The TFTP daemon should use secure mode. - + - + + + + + + + @@ -195990,7 +218601,7 @@ fi Oracle Linux 9 - Ensure RekeyLimit is configured with the appropriate value in /etc/ssh/sshd_config + Ensure RekeyLimit is configured with the appropriate value in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -196001,7 +218612,11 @@ fi - + + + + + @@ -196026,7 +218641,9 @@ fi + + @@ -196050,6 +218667,7 @@ fi + @@ -196073,6 +218691,7 @@ fi + @@ -196096,6 +218715,7 @@ fi + @@ -196145,29 +218765,6 @@ fi - - - Use Only Strong MACs - - Oracle Linux 9 - - - Ensure only strong MAC algorithms are used - - - - - - - - - - - - - - - Certificate status checking in SSSD @@ -196252,22 +218849,6 @@ fi - - - Log USBGuard daemon audit events using Linux Audit - - Oracle Linux 9 - - - Ensure 'AuditBackend' is configured with value 'LinuxAudit' in /etc/usbguard/usbguard-daemon.conf - - - - - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon @@ -196303,11 +218884,11 @@ fi Ensure that the default runlevel target is set to multi-user.target. - - - - - + + + + + @@ -196590,11 +219171,6 @@ fi Account Lockouts Must Be Logged - - - - - @@ -196618,19 +219194,8 @@ fi - - - - - - - - - - - @@ -196649,11 +219214,6 @@ fi Persist lockout account after reboot - - - - - @@ -196710,15 +219270,13 @@ fi The password retry should meet minimum requirements - - - - - - - - - + + + + + + + @@ -196742,7 +219300,7 @@ fi Oracle Linux 9 - The password hashing algorithm should be set correctly in /etc/login.defs. + The password hashing algorithm should be set correctly in /usr/etc/login.defs. @@ -196872,12 +219430,17 @@ fi The requirement for a password to boot into emergency mode should be configured correctly. - - - - - - + + + + + + + + + + + @@ -196954,27 +219517,27 @@ fi - + Set Account Expiration Following Inactivity in password-auth Oracle Linux 9 - The accounts should be configured to expire automatically following password expiration. + The accounts should be configured to be disabled automatically after a period of inactivity. - + Set Account Expiration Following Inactivity in system-auth Oracle Linux 9 - The accounts should be configured to expire automatically following password expiration. + The accounts should be configured to be disabled automatically after a period of inactivity. @@ -197481,7 +220044,7 @@ fi - + Set Interactive Session Timeout @@ -197494,6 +220057,7 @@ fi + @@ -197599,7 +220163,7 @@ fi - + @@ -197722,7 +220286,7 @@ fi Oracle Linux 9 - The default umask for all users specified in /etc/login.defs + The default umask for all users specified in {{{ login_defs_path }}} @@ -197795,19 +220359,6 @@ fi - - - Set the UEFI Boot Loader Password - - Oracle Linux 9 - - - The UEFI grub2 boot loader should have password protection enabled. - - - - - Configure Low Address Space To Protect From User Allocation @@ -197965,6 +220516,8 @@ fi + + @@ -198106,22 +220659,6 @@ fi - - - NetworkManager DNS Mode Must Be Must Configured - - Oracle Linux 9 - - - Ensure 'dns' is configured with value 'default|none in section 'main' in /etc/NetworkManager/NetworkManager.conf - - - - - - - - Ensure All World-Writable Directories Are Owned by root User @@ -198235,11 +220772,17 @@ fi - + + + + - + + + + @@ -198369,34 +220912,6 @@ fi - - - Disable core dump backtraces - - Oracle Linux 9 - - - Ensure 'ProcessSizeMax' is configured with value '0 in section 'Coredump' in /etc/systemd/coredump.conf - - - - - - - - - Disable storing core dump - - Oracle Linux 9 - - - Ensure 'Storage' is configured with value 'none in section 'Coredump' in /etc/systemd/coredump.conf - - - - - - Disable Core Dumps for All Users @@ -198501,19 +221016,6 @@ fi - - - Configure SELinux Policy - - Oracle Linux 9 - - - The SELinux policy should be set appropriately. - - - - - Ensure SELinux State is Enforcing @@ -198544,6 +221046,20 @@ fi + + + Encrypt Partitions + + Oracle Linux 9 + + + Verify all partitions are encrypted except /boot /boot/efi + + + + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles @@ -198883,31 +221399,6 @@ fi - - - The Installed Operating System Is FIPS 140-2 Certified - - Oracle Linux 9 - - - - The operating system installed on the system is a certified operating system that meets FIPS 140-2 requirements. - - - - - - - - - - - - - - - - The Installed Operating System Is Vendor Supported @@ -198920,14 +221411,19 @@ fi + + + + + @@ -199153,6 +221649,30 @@ fi + + + System Wide Crypto Policy Files Must Point to FIPS Policy + + Oracle Linux 9 + + + All system wide cryptopolicy symblinks should point to FIPS policy + + + + + + + + + + + + + + + + Set kernel parameter 'crypto.fips_enabled' to 1 @@ -199252,7 +221772,6 @@ fi cryptographic hashes. - @@ -199286,6 +221805,19 @@ fi + + + Verify crypto-policies with RPM + + Oracle Linux 9 + + + Verify the crypto-policies package using the RPM database. + + + + + Verify File Hashes with RPM @@ -199531,6 +222063,20 @@ fi + + + Ensure EPEL Repository is Disabled + + Oracle Linux 9 + + + The EPEL repository should be disabled or not present on the system. + + + + + + Ensure gpgcheck Enabled In Main yum Configuration @@ -199608,6 +222154,7 @@ fi + @@ -199625,6 +222172,7 @@ fi + @@ -199642,6 +222190,7 @@ fi + @@ -199659,6 +222208,7 @@ fi + @@ -199676,6 +222226,7 @@ fi + @@ -199693,6 +222244,7 @@ fi + @@ -199710,6 +222262,7 @@ fi + @@ -199727,6 +222280,7 @@ fi + @@ -199744,6 +222298,25 @@ fi + + + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session in /etc/security/pwquality.conf + + Oracle Linux 9 + + + The password retry should meet minimum requirements + + + + + + + + @@ -199761,6 +222334,7 @@ fi + @@ -199778,19 +222352,8 @@ fi - - - - - - - - - - - @@ -199814,19 +222377,8 @@ fi - - - - - - - - - - - @@ -199850,19 +222402,8 @@ fi - - - - - - - - - - - @@ -200340,17 +222881,21 @@ fi + + + + @@ -200368,17 +222913,21 @@ fi + + + + @@ -200424,17 +222973,21 @@ fi + + + + @@ -200452,17 +223005,21 @@ fi + + + + @@ -200480,17 +223037,21 @@ fi + + + + @@ -200508,17 +223069,21 @@ fi + + + + @@ -200551,6 +223116,26 @@ fi + + + Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ + + Oracle Linux 9 + + + Check if actions on '/etc/cron.d/' are configured to be audited + + + + + + + + + + + + Record Any Attempts to Run chacl @@ -200767,6 +223352,34 @@ fi + + + Ensure auditd Collects File Deletion Events by User - renameat2 + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - rmdir @@ -200851,63 +223464,187 @@ fi - + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - faillock Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on path specified in the 'var_accounts_passwords_pam_faillock_dir' variable are configured to be audited - + - + - + Record Attempts to Alter Logon and Logout Events - lastlog Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on '/var/log/lastlog' are configured to be audited - + - + - + Record Attempts to Alter Logon and Logout Events - tallylog Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on '/var/log/tallylog' are configured to be audited - + - + + + + + + + Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + + Oracle Linux 9 + + + Check if actions on '/etc/selinux/' are configured to be audited + + + + + + + + + + + + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + + Oracle Linux 9 + + + Check if actions on '/usr/share/selinux/' are configured to be audited + + + + + + + + + @@ -201399,6 +224136,126 @@ fi + + + Record Attempts to Alter Process and Session Initiation Information btmp + + Oracle Linux 9 + + + Check if actions on '/var/log/btmp' are configured to be audited + + + + + + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information utmp + + Oracle Linux 9 + + + Check if actions on '/var/run/utmp' are configured to be audited + + + + + + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information wtmp + + Oracle Linux 9 + + + Check if actions on '/var/log/wtmp' are configured to be audited + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + + Oracle Linux 9 + + + Check if actions on '/etc/sudoers' are configured to be audited + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + + Oracle Linux 9 + + + Check if actions on '/etc/sudoers.d/' are configured to be audited + + + + + + + + + + + + + + + Record Attempts to Alter the localtime File + + Oracle Linux 9 + + + Check if actions on '/etc/localtime' are configured to be audited + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - creat @@ -201622,16 +224479,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/group' are configured to be audited - + - + @@ -201642,16 +224499,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/gshadow' are configured to be audited - + - + @@ -201662,16 +224519,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/security/opasswd' are configured to be audited - + - + @@ -201682,16 +224539,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/passwd' are configured to be audited - + - + @@ -201702,36 +224559,56 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/shadow' are configured to be audited - + - + - + + + Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron + + Oracle Linux 9 + + + Check if actions on '/var/spool/cron' are configured to be audited + + + + + + + + + + + + + Record Attempts to perform maintenance activities Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on '/var/log/sudo.log' are configured to be audited - + - + @@ -201742,7 +224619,7 @@ fi Oracle Linux 9 - Ensure 'freq' is configured with value '50' in /etc/audit/auditd.conf + Ensure 'freq' is configured with value configured through XCCDF variable var_auditd_freq' in /etc/audit/auditd.conf @@ -201788,6 +224665,50 @@ fi + + + Log USBGuard daemon audit events using Linux Audit + + Oracle Linux 9 + + + Ensure 'AuditBackend' is configured with value 'LinuxAudit' in /etc/usbguard/usbguard-daemon.conf + + + + + + + + + + + Disable core dump backtraces + + Oracle Linux 9 + + + Ensure 'ProcessSizeMax' is configured with value '0' in section 'Coredump' in /etc/systemd/coredump.conf + + + + + + + + + Disable storing core dump + + Oracle Linux 9 + + + Ensure 'Storage' is configured with value 'none' in section 'Coredump' in /etc/systemd/coredump.conf + + + + + + Enable the GNOME3 Screen Locking On Smartcard Removal @@ -202143,7 +225064,7 @@ fi Oracle Linux 9 - Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -202155,8 +225076,9 @@ fi - - + + + @@ -202417,19 +225339,6 @@ fi - - - Verify the UEFI Boot Loader grub.cfg Group Ownership - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/grub.cfg is group owned by 0. - - - - - Verify /boot/grub2/user.cfg Group Ownership @@ -202873,32 +225782,6 @@ fi - - - Verify the UEFI Boot Loader grub.cfg User Ownership - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/grub.cfg is owned by 0. - - - - - - - - Verify /boot/grub2/user.cfg User Ownership - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/user.cfg is owned by 0. - - - - - Verify User Who Owns /etc/chrony.keys File @@ -203140,7 +226023,7 @@ fi Oracle Linux 9 - This test makes sure that /var/log/syslog is owned by 104. + This test makes sure that /var/log/syslog is owned by syslog. @@ -203398,36 +226281,6 @@ fi - - - Verify the UEFI Boot Loader grub.cfg Permissions - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/grub.cfg has mode 0700. - If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - Verify /boot/grub2/user.cfg Permissions - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/user.cfg has mode 0700. - If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - Verify Permissions on /etc/audit/auditd.conf @@ -203768,7 +226621,7 @@ fi Oracle Linux 9 - This test makes sure that /var/log/messages has mode 0600. + This test makes sure that /var/log/messages has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. @@ -203850,18 +226703,18 @@ fi Oracle Linux 9 - Ensure audit_backlog_limit=8192 is configured in the kernel line in /etc/default/grub. + Ensure audit_backlog_limit is configured in the kernel line in /etc/default/grub. - + - + - + @@ -205276,7 +228129,7 @@ fi - Stack Protector buffer overlow detection + Stack Protector buffer overflow detection Oracle Linux 9 @@ -205761,24 +228614,17 @@ fi - + Add nodev Option to /home Oracle Linux 9 - /home should be mounted with mount option nodev. + Home mount points should be mounted with mount option nodev. - - - - - - - - - + + @@ -206275,6 +229121,23 @@ fi + + + NetworkManager DNS Mode Must Be Must Configured + + Oracle Linux 9 + + + Ensure 'dns' is configured with value 'none|default' in section 'main' in /etc/NetworkManager/NetworkManager.conf + + + + + + + + + Install AIDE @@ -206821,32 +229684,6 @@ fi - - - Uninstall rsh-server Package - - Oracle Linux 9 - - - The RPM package rsh-server should be removed. - - - - - - - - Uninstall rsh Package - - Oracle Linux 9 - - - The RPM package rsh should be removed. - - - - - Ensure rsyslog-gnutls is installed @@ -207003,32 +229840,6 @@ fi - - - Uninstall talk-server Package - - Oracle Linux 9 - - - The RPM package talk-server should be removed. - - - - - - - - Uninstall talk Package - - Oracle Linux 9 - - - The RPM package talk should be removed. - - - - - Uninstall telnet-server Package @@ -207494,6 +230305,22 @@ fi + + + Configure SELinux Policy + + Oracle Linux 9 + + + Ensure 'SELINUXTYPE' is configured with value configured through XCCDF variable var_selinux_policy_name' in /etc/selinux/config + + + + + + + + Disable At Service (atd) @@ -207505,9 +230332,12 @@ fi - - - + + + + + + @@ -207542,9 +230372,12 @@ fi - - - + + + + + + @@ -207559,9 +230392,12 @@ fi - - - + + + + + + @@ -207616,9 +230452,12 @@ fi - - - + + + + + + @@ -207693,9 +230532,12 @@ fi - - - + + + + + + @@ -207710,9 +230552,12 @@ fi - - - + + + + + + @@ -207727,9 +230572,12 @@ fi - - - + + + + + + @@ -207784,9 +230632,12 @@ fi - - - + + + + + + @@ -207801,9 +230652,12 @@ fi - - - + + + + + + @@ -207838,9 +230692,12 @@ fi - - - + + + + + + @@ -207875,9 +230732,12 @@ fi - - - + + + + + + @@ -207892,9 +230752,12 @@ fi - - - + + + + + + @@ -207909,9 +230772,12 @@ fi - - - + + + + + + @@ -208019,9 +230885,12 @@ fi - - - + + + + + + @@ -208085,7 +230954,7 @@ fi Oracle Linux 9 - Ensure 'Protocol' is configured with value '2' in /etc/ssh/sshd_config + Ensure 'Protocol' is configured with value '2' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208097,8 +230966,9 @@ fi - - + + + @@ -208112,7 +230982,7 @@ fi Oracle Linux 9 - Ensure 'Compression' is configured with value configured in var_sshd_disable_compression variable in /etc/ssh/sshd_config + Ensure 'Compression' is configured with value configured in var_sshd_disable_compression variable in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208124,8 +230994,9 @@ fi - - + + + @@ -208139,7 +231010,7 @@ fi Oracle Linux 9 - Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208151,8 +231022,9 @@ fi - - + + + @@ -208166,7 +231038,7 @@ fi Oracle Linux 9 - Ensure 'GSSAPIAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'GSSAPIAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208178,8 +231050,9 @@ fi - - + + + @@ -208193,7 +231066,7 @@ fi Oracle Linux 9 - Ensure 'KerberosAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'KerberosAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208205,8 +231078,9 @@ fi - - + + + @@ -208220,7 +231094,7 @@ fi Oracle Linux 9 - Ensure 'PubkeyAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PubkeyAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208232,8 +231106,9 @@ fi - - + + + @@ -208247,7 +231122,7 @@ fi Oracle Linux 9 - Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208259,8 +231134,9 @@ fi - - + + + @@ -208274,7 +231150,7 @@ fi Oracle Linux 9 - Ensure 'RhostsRSAAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'RhostsRSAAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208286,8 +231162,9 @@ fi - - + + + @@ -208301,7 +231178,7 @@ fi Oracle Linux 9 - Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208313,8 +231190,9 @@ fi - - + + + @@ -208328,7 +231206,7 @@ fi Oracle Linux 9 - Ensure 'PermitRootLogin' is configured with value 'prohibit-password' in /etc/ssh/sshd_config + Ensure 'PermitRootLogin' is configured with value 'prohibit-password' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208340,8 +231218,9 @@ fi - - + + + @@ -208355,7 +231234,7 @@ fi Oracle Linux 9 - Ensure 'AllowTcpForwarding' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'AllowTcpForwarding' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208367,8 +231246,9 @@ fi - - + + + @@ -208382,7 +231262,7 @@ fi Oracle Linux 9 - Ensure 'IgnoreUserKnownHosts' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'IgnoreUserKnownHosts' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208394,8 +231274,9 @@ fi - - + + + @@ -208409,7 +231290,7 @@ fi Oracle Linux 9 - Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208421,8 +231302,9 @@ fi - - + + + @@ -208436,7 +231318,7 @@ fi Oracle Linux 9 - Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208448,8 +231330,9 @@ fi - - + + + @@ -208463,7 +231346,7 @@ fi Oracle Linux 9 - Ensure 'GSSAPIAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'GSSAPIAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208475,8 +231358,9 @@ fi - - + + + @@ -208490,7 +231374,7 @@ fi Oracle Linux 9 - Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208502,8 +231386,9 @@ fi - - + + + @@ -208517,7 +231402,7 @@ fi Oracle Linux 9 - Ensure 'PubkeyAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'PubkeyAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208529,8 +231414,9 @@ fi - - + + + @@ -208544,7 +231430,7 @@ fi Oracle Linux 9 - Ensure 'StrictModes' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'StrictModes' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208556,8 +231442,9 @@ fi - - + + + @@ -208571,7 +231458,7 @@ fi Oracle Linux 9 - Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config + Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208583,8 +231470,9 @@ fi - - + + + @@ -208598,7 +231486,7 @@ fi Oracle Linux 9 - Ensure 'Banner' is configured with value '/etc/issue.net' in /etc/ssh/sshd_config + Ensure 'Banner' is configured with value '/etc/issue.net' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208610,8 +231498,9 @@ fi - - + + + @@ -208625,7 +231514,7 @@ fi Oracle Linux 9 - Ensure 'X11Forwarding' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'X11Forwarding' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208637,8 +231526,9 @@ fi - - + + + @@ -208665,7 +231555,7 @@ fi Oracle Linux 9 - Ensure 'PrintLastLog' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'PrintLastLog' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208677,8 +231567,9 @@ fi - - + + + @@ -208692,7 +231583,7 @@ fi Oracle Linux 9 - Ensure 'ClientAliveCountMax' is configured with value configured in var_sshd_set_keepalive variable in /etc/ssh/sshd_config + Ensure 'ClientAliveCountMax' is configured with value configured in var_sshd_set_keepalive variable in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208704,8 +231595,9 @@ fi - - + + + @@ -208719,7 +231611,7 @@ fi Oracle Linux 9 - Ensure 'ClientAliveCountMax' is configured with value '0' in /etc/ssh/sshd_config + Ensure 'ClientAliveCountMax' is configured with value '0' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208731,8 +231623,9 @@ fi - - + + + @@ -208746,7 +231639,7 @@ fi Oracle Linux 9 - Ensure 'LogLevel' is configured with value 'INFO' in /etc/ssh/sshd_config + Ensure 'LogLevel' is configured with value 'INFO' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208758,8 +231651,9 @@ fi - - + + + @@ -208773,7 +231667,7 @@ fi Oracle Linux 9 - Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config + Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208785,8 +231679,9 @@ fi - - + + + @@ -208800,7 +231695,7 @@ fi Oracle Linux 9 - Ensure 'UsePrivilegeSeparation' is configured with value configured in var_sshd_priv_separation variable in /etc/ssh/sshd_config + Ensure 'UsePrivilegeSeparation' is configured with value configured in var_sshd_priv_separation variable in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208812,8 +231707,9 @@ fi - - + + + @@ -208827,7 +231723,7 @@ fi Oracle Linux 9 - Ensure 'X11UseLocalhost' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'X11UseLocalhost' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208839,8 +231735,9 @@ fi - - + + + @@ -208867,7 +231764,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults noexec configuration @@ -208880,7 +231777,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults requiretty configuration @@ -208893,7 +231790,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults use_pty configuration @@ -208906,7 +231803,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults logfile configuration @@ -210102,7 +232999,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces Oracle Linux 9 @@ -210116,7 +233013,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces Oracle Linux 9 @@ -210129,7 +233026,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces Oracle Linux 9 @@ -210297,10 +233194,10 @@ fi Oracle Linux 9 - The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system runtime. + The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to the appropriate value in the system runtime. - + @@ -210310,13 +233207,13 @@ fi Oracle Linux 9 - The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system configuration. + The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to the appropriate value in the system configuration. - + - + @@ -210542,7 +233439,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default Oracle Linux 9 @@ -210556,7 +233453,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default Oracle Linux 9 @@ -210569,7 +233466,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default Oracle Linux 9 @@ -212162,7 +235059,7 @@ fi - Record Any Attempts to Run semanage + Test if auditctl is in use for audit rules Oracle Linux 9 @@ -212175,7 +235072,7 @@ fi - Record Any Attempts to Run semanage + Test if augenrules is enabled for audit rules Oracle Linux 9 @@ -212199,18 +235096,18 @@ fi - + - + - + - + @@ -212228,18 +235125,18 @@ fi - + - + - + - + @@ -212285,6 +235182,10 @@ fi + + + + @@ -212315,6 +235216,22 @@ fi + + + AlmaLinux OS 9 + + Oracle Linux 9 + + + + The operating system installed on the system is AlmaLinux OS 9 + + + + + + + Oracle Linux 7 @@ -212382,21 +235299,25 @@ fi - + - Red Hat Enterprise Linux CoreOS + Red Hat Enterprise Linux 10 Oracle Linux 9 - - + + The operating system installed on the system is - Red Hat Enterprise Linux CoreOS release 4 + Red Hat Enterprise Linux 10 - - - + + + + + + + @@ -212494,6 +235415,25 @@ fi + + + SUSE Linux Enterprise 16 + + Oracle Linux 9 + + + + The operating system installed on the system is SUSE Linux Enterprise Server 16. + + + + + + + + + + SUSE Linux Enterprise Micro @@ -212516,6 +235456,25 @@ fi + + + SUSE Linux Enterprise Micro + + Oracle Linux 9 + + + + + The operating system installed on the system is + SUSE Linux Micro. + + + + + + + + Ubuntu @@ -212531,49 +235490,19 @@ fi - + - Ubuntu 16.04 LTS + Ubuntu 24.04 LTS Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 16.04 LTS + + + The operating system installed on the system is Ubuntu 24.04 LTS - + - - - - - - Ubuntu 18.04 LTS - - Oracle Linux 9 - - - - The operating system installed on the system is Ubuntu 18.04 LTS - - - - - - - - - Ubuntu 20.04 LTS - - Oracle Linux 9 - - - - The operating system installed on the system is Ubuntu 20.04 LTS - - - - + @@ -212803,65 +235732,29 @@ fi - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -212887,18 +235780,6 @@ fi - - - - - - - - - - - - @@ -212937,11 +235818,17 @@ fi - - + + - - + + + + + + + + @@ -212966,14 +235853,6 @@ fi - - - - - - - - @@ -213006,42 +235885,6 @@ fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -213108,12 +235951,6 @@ fi - - - - - - @@ -213157,6 +235994,10 @@ fi + + + + @@ -213259,7 +236100,7 @@ fi - + @@ -213275,6 +236116,9 @@ fi + + + @@ -213299,9 +236143,15 @@ fi - - - + + + + + + + + + @@ -213325,7 +236175,7 @@ fi - + @@ -213354,11 +236204,28 @@ fi + + + + + + + + + + + + + + + + + @@ -213367,6 +236234,11 @@ fi + + + + + @@ -213375,6 +236247,11 @@ fi + + + + + @@ -213383,6 +236260,11 @@ fi + + + + + @@ -213401,10 +236283,6 @@ fi - - - - @@ -213441,21 +236319,17 @@ fi - - - - - - - - - + + - - + + - - + + + + + @@ -213613,71 +236487,33 @@ fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -213685,9 +236521,6 @@ fi - - - @@ -213702,22 +236535,11 @@ fi - - - - - - - - - - - @@ -213775,6 +236597,9 @@ fi + + + @@ -214029,6 +236854,10 @@ fi + + + + @@ -214136,9 +236965,6 @@ fi - - - @@ -214246,6 +237072,12 @@ fi + + + + + + @@ -214263,7 +237095,7 @@ fi - + @@ -214305,13 +237137,6 @@ fi - - - - - - - @@ -214352,6 +237177,9 @@ fi + + + @@ -214401,22 +237229,6 @@ fi - - - - - - - - - - - - - - - - @@ -214425,7 +237237,7 @@ fi - + @@ -214462,10 +237274,6 @@ fi - - - - @@ -214482,6 +237290,12 @@ fi + + + + + + @@ -214556,6 +237370,7 @@ fi + @@ -214688,6 +237503,54 @@ fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -214759,6 +237622,9 @@ fi + + + @@ -214852,6 +237718,13 @@ fi + + + + + + + @@ -214872,6 +237745,9 @@ fi + + + @@ -214879,6 +237755,9 @@ fi + + + @@ -214886,6 +237765,9 @@ fi + + + @@ -214893,6 +237775,9 @@ fi + + + @@ -214900,6 +237785,9 @@ fi + + + @@ -214908,6 +237796,9 @@ fi + + + @@ -214915,6 +237806,9 @@ fi + + + @@ -214922,6 +237816,9 @@ fi + + + @@ -214929,13 +237826,30 @@ fi + + + + + + + + + + + + + + + + + @@ -214943,123 +237857,52 @@ fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -215232,6 +238075,18 @@ fi + + + + + + + + + + + + @@ -215244,6 +238099,18 @@ fi + + + + + + + + + + + + @@ -215268,6 +238135,18 @@ fi + + + + + + + + + + + + @@ -215280,6 +238159,18 @@ fi + + + + + + + + + + + + @@ -215292,6 +238183,18 @@ fi + + + + + + + + + + + + @@ -215304,6 +238207,18 @@ fi + + + + + + + + + + + + @@ -215316,6 +238231,12 @@ fi + + + + + + @@ -215388,6 +238309,18 @@ fi + + + + + + + + + + + + @@ -215424,23 +238357,71 @@ fi - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -215592,6 +238573,42 @@ fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -215736,41 +238753,47 @@ fi - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - + + + + + + + + @@ -215791,6 +238814,29 @@ fi + + + + + + + + + + + + + + + + + + + + + + + @@ -215932,6 +238978,10 @@ fi + + + + @@ -216043,9 +239093,6 @@ fi - - - @@ -216151,12 +239198,6 @@ fi - - - - - - @@ -216280,12 +239321,6 @@ fi - - - - - - @@ -216386,15 +239421,15 @@ fi - + - + - + @@ -217360,20 +240395,10 @@ fi - - - + + + - - - - - - - - - - @@ -217664,6 +240689,17 @@ fi + + + + + + + + + + + @@ -217790,12 +240826,6 @@ fi - - - - - - @@ -217832,12 +240862,6 @@ fi - - - - - - @@ -217865,9 +240889,6 @@ fi - - - @@ -217960,6 +240981,13 @@ fi + + + + + + + @@ -217968,6 +240996,10 @@ fi + + + + @@ -217994,6 +241026,10 @@ fi + + + + @@ -218005,6 +241041,10 @@ fi + + + + @@ -218046,6 +241086,10 @@ fi + + + + @@ -218102,6 +241146,10 @@ fi + + + + @@ -218113,6 +241161,10 @@ fi + + + + @@ -218124,6 +241176,10 @@ fi + + + + @@ -218165,6 +241221,10 @@ fi + + + + @@ -218176,6 +241236,10 @@ fi + + + + @@ -218202,6 +241266,10 @@ fi + + + + @@ -218228,6 +241296,10 @@ fi + + + + @@ -218239,6 +241311,10 @@ fi + + + + @@ -218250,6 +241326,10 @@ fi + + + + @@ -218325,6 +241405,10 @@ fi + + + + @@ -218369,6 +241453,10 @@ fi + + + + @@ -218380,6 +241468,10 @@ fi + + + + @@ -218391,6 +241483,10 @@ fi + + + + @@ -218402,6 +241498,10 @@ fi + + + + @@ -218413,6 +241513,10 @@ fi + + + + @@ -218424,6 +241528,10 @@ fi + + + + @@ -218435,6 +241543,10 @@ fi + + + + @@ -218446,6 +241558,10 @@ fi + + + + @@ -218457,6 +241573,10 @@ fi + + + + @@ -218468,6 +241588,10 @@ fi + + + + @@ -218479,6 +241603,10 @@ fi + + + + @@ -218490,6 +241618,10 @@ fi + + + + @@ -218501,6 +241633,10 @@ fi + + + + @@ -218512,6 +241648,10 @@ fi + + + + @@ -218523,6 +241663,10 @@ fi + + + + @@ -218534,6 +241678,10 @@ fi + + + + @@ -218545,6 +241693,10 @@ fi + + + + @@ -218556,6 +241708,10 @@ fi + + + + @@ -218567,6 +241723,10 @@ fi + + + + @@ -218578,6 +241738,10 @@ fi + + + + @@ -218589,6 +241753,10 @@ fi + + + + @@ -218603,6 +241771,10 @@ fi + + + + @@ -218614,6 +241786,10 @@ fi + + + + @@ -218625,6 +241801,10 @@ fi + + + + @@ -218636,6 +241816,10 @@ fi + + + + @@ -218647,6 +241831,10 @@ fi + + + + @@ -218658,6 +241846,10 @@ fi + + + + @@ -218669,6 +241861,10 @@ fi + + + + @@ -219159,23 +242355,20 @@ fi - + - - + - - + - - + @@ -219795,29 +242988,29 @@ fi - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -219840,6 +243033,13 @@ fi + + + + + + + @@ -219847,6 +243047,12 @@ fi + + + + + + @@ -219863,13 +243069,17 @@ fi - - - - - - - + + + + + + + + + + + @@ -219939,6 +243149,22 @@ fi + + + + + + + + + + + + + + + + @@ -219951,20 +243177,22 @@ fi + + + + + + + + - - - - - - - - + + @@ -220050,106 +243278,46 @@ fi ^\-w[\s]+/etc/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers\.d/?[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers\.d/?[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -220190,26 +243358,6 @@ fi ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - ^/etc/audit/rules\.d/.*\.rules$ ^\-f\s+(\d)\s*$ @@ -220270,15 +243418,25 @@ fi ^\-w[\s]+/etc/security/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ - - 1 + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 - - /etc/audit/audit.rules - - 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 @@ -220323,18 +243481,6 @@ fi oval:ssg-state_not_mode_0700:ste:1 - - - /var/log/audit - - oval:ssg-state_not_mode_0750:ste:1 - - - - - - oval:ssg-state_not_mode_0750:ste:1 - oval:ssg-state_group_owner_not_root_var_log_audit:ste:1 @@ -220385,66 +243531,6 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount[\s]+|([\s]+|[,])umount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - ^(?!/proc(/.*|$)).*$ oval:ssg-state_audit_rules_privileged_commands_dev_partitons:ste:1 @@ -220560,16 +243646,6 @@ fi ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+stime[\s]+|([\s]+|[,])stime([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - /etc/audit/plugins.d/syslog.conf ^[ ]*active[ ]+=[ ]+yes[ ]*$ @@ -220598,13 +243674,18 @@ fi /etc/audit/auditd.conf ^[ ]*action_mail_acct[ ]+=[ ]+(\S+)[ ]*$ - 1 + 1 /etc/audit/auditd.conf ^[ ]*admin_space_left_action[ ]+=[ ]+(\S+)[ ]*$ 1 + + /etc/audit/auditd.conf + ^[\s]*admin_space_left[\s]+=[\s]+(\d+)%[\s]*$ + 1 + /etc/audit/auditd.conf ^[ ]*flush[ ]+=[ ]+(\S+)[ ]*$ @@ -220740,12 +243821,12 @@ fi 0 - ^/etc/chrony\.(conf|d/.+\.conf)$ + ^(/etc/chrony\.conf|/etc/chrony\.d/.+\.conf)$ ^[\s]*server.*$ 1 - - ^/etc/chrony\.(conf|d/.+\.conf)$ + + ^(/etc/chrony\.conf|/etc/chrony\.d/.+\.conf)$ ^[\s]+pool.*$ 1 @@ -220759,6 +243840,9 @@ fi ^\s*group:\s+(.*)$ 1 + + nss-altfiles + /etc/chrony.keys oval:ssg-state_file_groupowner_etc_chrony_keys_uid_chrony:ste:1 @@ -220766,7 +243850,7 @@ fi /etc/group - ^chrony:\w+:(\w+):.* + ^chrony:[\w!]+:(\w+):.* 1 @@ -220782,7 +243866,7 @@ fi /usr/lib/group - ^chrony:\w+:(\w+):.* + ^chrony:[\w!]+:(\w+):.* 1 @@ -220813,9 +243897,15 @@ fi / .shosts - - /etc/xinetd.d/tftp - ^[\s]*server_args[\s]+=[\s]+.*?-s[\s]+([/\.\w]+).*$ + + /etc/systemd/system/tftp.service.d + .*\.conf$ + ^\s*ExecStart=\s*(?:.*\n)*?(\s*ExecStart=.+)$ + 1 + + + /usr/lib/systemd/system/tftp.service + ^\s*ExecStart\s*=\s*/\S+\s+-s\s+(/\S+).*$ 1 @@ -220912,14 +244002,37 @@ fi ^[\s]*RekeyLimit[\s]+(.*)$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[\s]*RekeyLimit[\s]+(.*)$ + 1 + /etc/ssh/sshd_config ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + + + /etc/ssh/sshd_config + (?i)^\s*Include\s+(.*)$ + 1 + + + + ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + oval:ssg-object_sshd_idle_timeout:obj:1 + oval:ssg-object_sshd_idle_timeout_config_dir:obj:1 @@ -220927,9 +244040,16 @@ fi ^[\s]*(?i)LoginGraceTime[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)LoginGraceTime(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-object_sshd_login_grace_time:obj:1 + oval:ssg-obj_sshd_set_login_grace_time_config_dir:obj:1 @@ -220937,9 +244057,16 @@ fi ^[\s]*(?i)MaxAuthTries[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)MaxAuthTries(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-object_sshd_max_auth_tries:obj:1 + oval:ssg-obj_sshd_set_max_auth_tries_config_dir:obj:1 @@ -220947,9 +244074,16 @@ fi ^[\s]*(?i)MaxSessions[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)MaxSessions(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-object_sshd_max_sessions:obj:1 + oval:ssg-obj_sshd_set_max_sessions_config_dir:obj:1 @@ -220975,14 +244109,6 @@ fi ^[ \t]*(?i)match(?-i)\s+\S+ 1 - - oval:ssg-var_sshd_config_strong_macs:var:1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)MACs(?-i)[\s]+([\w,-@]+)+[\s]*(?:#.*)?$ - 1 - ^/etc/sssd/(sssd|conf\.d/.*)\.conf$ ^[\s]*\[sssd](?:[^\n\[]*\n+)+?[\s]*certificate_verification\s*=\s*ocsp_dgst=(\w+)$ @@ -221028,21 +244154,16 @@ fi ^[\s]*\[domain\/[^]]*](?:[^\n\[\]]*\n+)+?[\s]*ldap_id_use_start_tls[ \t]*=[ \t]*((?i)\w+)[ \t]*$ 1 - - /etc/usbguard/usbguard-daemon.conf - ^[ \t]*AuditBackend=(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/usbguard/usbguard-daemon.conf - - + xorg-x11-server-Xorg - + + xorg-x11-server-common + + xorg-x11-server-utils - + xorg-x11-server-Xwayland @@ -221115,7 +244236,7 @@ fi /etc/pam.d/postlogin - ^\s*session\s+.*\s+pam_lastlog\.so\b(?!.*\ssilent\s).*\sshowfailed\s.*$ + ^\s*session\s+.*\s+pam_lastlog.so\b(?!.*\ssilent\s).*\sshowfailed\s.*$ 1 @@ -221149,7 +244270,7 @@ fi 1 - /etc/pam.d/password-auth|/etc/pam.d/system-auth|/etc/security/faillock.conf + /etc/security/faillock.conf ^\s*(?:auth.*pam_faillock\.so.*)?dir\s*=\s*(\S+) 1 @@ -221250,26 +244371,6 @@ fi 1 - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - ^/etc/pam.d/system-auth$ @@ -221297,19 +244398,13 @@ fi 1 oval:ssg-state_pam_faillock_dir_parameter_not_default_value:ste:1 - - oval:ssg-var_faillock_dir_set_both_preauth_authfail_system_auth:var:1 - - - oval:ssg-var_faillock_dir_set_both_preauth_authfail_password_auth:var:1 - /etc/security/faillock.conf 1 - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^enforce_for_root$ 1 @@ -221333,11 +244428,6 @@ fi ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$ 1 - - /etc/security/pwquality.conf - ^[\s]*retry[\s]*=[\s]*(\d+)(?:[\s]|$) - 1 - /etc/libuser.conf ^[\s]*crypt_style[\s]*=[\s]*(\w*)[\s]*$ @@ -221416,6 +244506,12 @@ fi ^ExecStart=\-/usr/lib/systemd/systemd-sulogin-shell[\s]+emergency 1 + + /etc/systemd/system/emergency.service.d + ^.*\.conf$ + ^ExecStart=\-/usr/lib/systemd/systemd-sulogin-shell[\s]+emergency + 1 + /usr/lib/systemd/system/emergency.target ^Requires=.*emergency\.service @@ -221601,7 +244697,7 @@ fi ^/etc/pam.d/password-auth$ - ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*rounds=([0-9]*).*$ + ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so[^#]*rounds=([0-9]*).*$ 1 @@ -222107,7 +245203,7 @@ fi /boot/grub2/grub.cfg - ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)"$ + ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)".*\n[\s]*export[\s]+superusers[\s]*$ 1 @@ -222115,11 +245211,6 @@ fi ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ 1 - - /boot/grub2/user.cfg - ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ - 1 - ^/boot/config-.*$ ^CONFIG_DEFAULT_MMAP_MIN_ADDR="?(.*?)"?$ @@ -222149,7 +245240,7 @@ fi /etc/rsyslog.conf - (?m)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ + (?ms)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ 1 @@ -222161,18 +245252,18 @@ fi /etc/rsyslog.d ^.*$ - (?m)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ + (?ms)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ 1 /etc/rsyslog.conf - (?m)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ + (?ms)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ 1 /etc/rsyslog.d ^.*$ - (?m)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ + (?ms)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ 1 @@ -222182,7 +245273,7 @@ fi /etc/rsyslog.conf - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ 1 @@ -222194,7 +245285,7 @@ fi /etc/rsyslog.d ^.*conf$ - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ 1 @@ -222204,7 +245295,7 @@ fi /etc/rsyslog.conf - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ 1 @@ -222216,7 +245307,7 @@ fi /etc/rsyslog.d ^.*conf$ - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ 1 @@ -222226,7 +245317,7 @@ fi /etc/rsyslog.conf - ^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ + (?ms)^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ 1 @@ -222238,22 +245329,22 @@ fi /etc/rsyslog.d ^.*conf$ - ^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ + (?ms)^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ 1 ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*auth\.\*.*$ + ^[^#\n]*auth(,\w+)*\.\*[^\n]*$ 1 ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*authpriv\.\*.*$ + ^[^#\n]*authpriv(,\w+)*\.\*[^\n]*$ 1 ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*daemon\.\*.*$ + ^[^#\n]*daemon(,\w+)*\.\*[^\n]*$ 1 @@ -222296,6 +245387,17 @@ fi ^\*\.\*[\s]+(?:@|\:omrelp\:) 1 + + /etc/rsyslog.conf + (?ms)^\s*\*\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfwd"\s*.*(?i)\btarget\b(?-i)="\S+"\s*.*\)\s*$ + 1 + + + /etc/rsyslog.d + ^.+\.conf$ + (?ms)^\s*\*\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfwd"\s*.*(?i)\btarget\b(?-i)="\S+"\s*.*\)\s*$ + 1 + ^/etc/rsyslog\.(conf|d/.+\.conf)$ @@ -222373,14 +245475,6 @@ fi ^wl.*$ - - /etc/NetworkManager/NetworkManager.conf - ^\s*\[main\].*(?:\n\s*[^[\s].*)*\ndns=([^#]*).*$ - 1 - - - ^/etc/NetworkManager/NetworkManager.conf - / @@ -222537,6 +245631,9 @@ fi ^\s*group:\s+(.*)$ 1 + + nss-altfiles + .* @@ -222554,6 +245651,7 @@ fi ^\/s?bin|^\/usr\/s?bin|^\/usr\/local\/s?bin ^.*$ oval:ssg-state_groupowner_system_commands_dirs_not_root_or_system_account:ste:1 + oval:ssg-state_groupowner_system_commands_dirs_symlink:ste:1 ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec @@ -222642,37 +245740,15 @@ fi ^[[:blank:]]*kernel.core_pattern[[:blank:]]*=[[:blank:]]*(.*)$ 1 - - /etc/systemd/coredump.conf - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf.d - .*\.conf$ - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf.d - .*\.conf$ - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - /etc/security/limits.conf - ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) + ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\S]+) 1 /etc/security/limits.d ^.*\.conf$ - ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) + ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\S]+) 1 @@ -222682,7 +245758,7 @@ fi 1 - /boot/grub2/grub.cfg + /etc/default/grub [\s]*noexec[\s]*=[\s]*off 1 @@ -222737,11 +245813,6 @@ fi ^SELINUX=(.*)$ 1 - - /etc/selinux/config - ^SELINUXTYPE=([\w]*)[\s]*$ - 1 - /etc/selinux/config ^SELINUX=(.*)$ @@ -222760,6 +245831,17 @@ fi ^.*\.(.*)$ 1 + + ^(?!\/boot(?:\/efi)?$).* + oval:ssg-state_encrypted_partitions:ste:1 + oval:ssg-state_non_temporary_partitions:ste:1 + oval:ssg-state_non_pseudo_file_systems:ste:1 + + + /etc/crypttab + ^\s*(\S+) + 1 + /etc/dconf/db/local @@ -223055,7 +246137,7 @@ fi /etc/crypto-policies/back-ends/opensshserver.config ^(?!#).*Ciphers\s+([^\s']+).*$ - 1 + -1 /etc/crypto-policies/back-ends/openssh.config @@ -223064,8 +246146,8 @@ fi /etc/crypto-policies/back-ends/opensshserver.config - ^(?!#).*(-oMACs=\S+).+$ - 1 + ^(?!#).*MACs\s+([^\s']+).*$ + -1 ^mfetpd.*$ @@ -223092,12 +246174,48 @@ fi /etc/system-fips + + /etc/crypto-policies/back-ends/bind.config + + + /etc/crypto-policies/back-ends/gnutls.config + + + /etc/crypto-policies/back-ends/java.config + + + /etc/crypto-policies/back-ends/javasystem.config + + + /etc/crypto-policies/back-ends/krb5.config + + + /etc/crypto-policies/back-ends/libreswan.config + + + /etc/crypto-policies/back-ends/libssh.config + + + /etc/crypto-policies/back-ends/openssh.config + + + /etc/crypto-policies/back-ends/opensshserver.config + + + /etc/crypto-policies/back-ends/opensslcnf.config + + + /etc/crypto-policies/back-ends/openssl.config + + + /etc/crypto-policies/back-ends/openssl_fips.config + crypto.fips_enabled /etc/aide.conf - ^database=file:@@{DBDIR}/([a-z.]+)$ + ^database=file:(?:@@{DBDIR})?/(?:[a-z.]+/)*([a-z.]+)$ 1 @@ -223110,37 +246228,37 @@ fi /etc/aide.conf - ^\/usr\/sbin\/auditctl\s+([^\n]+)$ + ^(?:/usr)?/sbin/auditctl\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/auditd\s+([^\n]+)$ + ^(?:/usr)?/sbin/auditd\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/ausearch\s+([^\n]+)$ + ^(?:/usr)?/sbin/ausearch\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/aureport\s+([^\n]+)$ + ^(?:/usr)?/sbin/aureport\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/autrace\s+([^\n]+)$ + ^(?:/usr)?/sbin/autrace\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/rsyslogd\s+([^\n]+)$ + ^(?:/usr)?/sbin/rsyslogd\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/augenrules\s+([^\n]+)$ + ^(?:/usr)?/sbin/augenrules\s+([^\n]+)$ 1 @@ -223201,6 +246319,15 @@ fi ^(?!ALLXTRAHASHES)[A-Z][a-zA-Z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ 1 + + crypto-policies + .* + .* + .* + .* + .* + oval:ssg-state_rpm_verify_crypto_policies:ste:1 + .* @@ -223363,6 +246490,16 @@ fi ^/etc/dnf/automatic.conf + + ^/etc/yum\.repos\.d/.*\.repo$ + (?i)^\s*\[[^\]]*epel[^\]]*\] + 1 + + + ^/etc/yum\.repos\.d/.*\.repo$ + (?i)(?:^\s*\[[^\]]*epel[^\]]*\][\s\S]*?)^\s*enabled\s*=\s*(\S+) + 1 + /etc/yum.conf ^\s*gpgcheck\s*=\s*(1|True|yes)\s*$ @@ -223387,8 +246524,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bdcredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bdcredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*dcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223397,8 +246539,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bdictcheck\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bdictcheck\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*dictcheck[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223407,8 +246554,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bdifok\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bdifok\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*difok[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223417,8 +246569,13 @@ fi ^\s*password.*pam_pwquality\.so.*\blcredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\blcredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*lcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223427,8 +246584,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bmaxclassrepeat\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bmaxclassrepeat\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*maxclassrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223437,8 +246599,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bmaxrepeat\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bmaxrepeat\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*maxrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223447,8 +246614,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bminclass\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bminclass\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*minclass[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223457,8 +246629,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bminlen\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bminlen\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*minlen[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223467,18 +246644,43 @@ fi ^\s*password.*pam_pwquality\.so.*\bocredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bocredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*ocredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bretry\b + 1 + + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bretry\b + 1 + + + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ + ^\s*retry[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + /etc/pam.d/system-auth ^\s*password.*pam_pwquality\.so.*\bucredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bucredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*ucredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223487,31 +246689,11 @@ fi 1 - - /etc/pam.d/system-auth - - 1 - /etc/pam.d/password-auth 1 - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - /etc/pam.d/system-auth @@ -223532,31 +246714,11 @@ fi 1 - - /etc/pam.d/system-auth - - 1 - /etc/pam.d/password-auth 1 - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - /etc/pam.d/system-auth @@ -223577,31 +246739,11 @@ fi 1 - - /etc/pam.d/system-auth - - 1 - /etc/pam.d/password-auth 1 - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - /etc/pam.d/system-auth @@ -223719,7 +246861,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/init(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223729,7 +246871,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/poweroff(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223739,7 +246881,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/reboot(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223749,7 +246891,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/shutdown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223893,6 +247035,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223913,6 +247075,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223953,6 +247135,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223973,6 +247175,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223993,6 +247215,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -224013,6 +247255,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -224033,13 +247295,23 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224049,7 +247321,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chcon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224059,7 +247331,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/restorecon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224069,7 +247341,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/semanage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224079,7 +247351,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/setfacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224089,7 +247361,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setfiles(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224099,7 +247371,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setsebool(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224109,7 +247381,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/seunshare(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224153,6 +247425,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -224213,34 +247505,114 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - /etc/audit/audit.rules - - 1 - - + ^/etc/audit/rules\.d/.*\.rules$ - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + ^/etc/audit/rules\.d/.*\.rules$ - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + /etc/audit/audit.rules - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + 1 @@ -224269,7 +247641,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/at(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224279,7 +247651,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224289,7 +247661,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chsh(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224299,7 +247671,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/crontab(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224309,7 +247681,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/gpasswd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224319,7 +247691,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/kmod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224329,7 +247701,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/mount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224339,7 +247711,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/newgrp(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224349,7 +247721,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/pam_timestamp_check(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224359,7 +247731,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/passwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224369,7 +247741,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postdrop(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224379,7 +247751,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postqueue(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224389,7 +247761,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/ssh-agent(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224399,7 +247771,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/openssh\/ssh-keysign(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224409,7 +247781,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/su(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224419,7 +247791,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudo(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224429,7 +247801,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudoedit(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224439,7 +247811,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/umount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224449,7 +247821,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_chkpwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224459,7 +247831,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_update(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224469,7 +247841,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/userhelper(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224479,7 +247851,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usermod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224489,10 +247861,70 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usernetctl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + ^/etc/audit/rules\.d/.*\.rules$ @@ -224733,64 +248165,74 @@ fi 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - + 1 - + /etc/audit/audit.rules - + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + 1 @@ -224818,6 +248260,36 @@ fi ^[ \t]*(?i)write_logs(?-i)[ \t]*=[ \t]* 1 + + /etc/usbguard/usbguard-daemon.conf + ^[ \\t]*AuditBackend=(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/usbguard/usbguard-daemon.conf + + + /etc/systemd/coredump.conf + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*ProcessSizeMax\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf.d + .*\.conf$ + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*ProcessSizeMax\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*Storage\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf.d + .*\.conf$ + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*Storage\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + /etc/dconf/db/local.d/ ^.*$ @@ -224834,99 +248306,99 @@ fi /lib - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /lib64 - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_1:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /usr/lib - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_2:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /usr/lib64 - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_3:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /bin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /sbin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/bin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_2:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/sbin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_3:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/local/bin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_4:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/local/sbin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_5:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /lib - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 /lib64 - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 /usr/lib - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_2:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 /usr/lib64 - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_3:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 @@ -224998,107 +248470,173 @@ fi oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 oval:ssg-state_file_permissionsdir_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 - - /etc/ipsec.d - - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_ipsecd_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_ipsecd_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_ipsecd_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_ipsecd_root_gid_usr:obj:1 + + + + /etc/ipsec.d + + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_ipsecd_0_root:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_iptables_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_iptables_root_gid_usr:obj:1 + + /etc/iptables - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_iptables_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_iptables_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_iptables_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_nftables_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_nftables_root_gid_usr:obj:1 + + /etc/nftables - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_nftables_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_nftables_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_nftables_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_selinux_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_selinux_root_gid_usr:obj:1 + + /etc/selinux - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_selinux_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_selinux_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_selinux_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sudoersd_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sudoersd_root_gid_usr:obj:1 + + /etc/sudoers.d - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_sudoersd_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_sudoersd_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_sudoersd_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sysctld_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sysctld_root_gid_usr:obj:1 + + /etc/sysctl.d - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_sysctld_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_sysctld_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_sysctld_0_root:ste:1 - - /etc/group - ^root:\w+:(\w+):.* - 1 - /etc/ipsec.d - oval:ssg-symlink_file_ownerdirectory_owner_etc_ipsecd_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_ipsecd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_ipsecd_0_0:ste:1 /etc/iptables - oval:ssg-symlink_file_ownerdirectory_owner_etc_iptables_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_iptables_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_iptables_0_0:ste:1 /etc/nftables - oval:ssg-symlink_file_ownerdirectory_owner_etc_nftables_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_nftables_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_nftables_0_0:ste:1 /etc/selinux - oval:ssg-symlink_file_ownerdirectory_owner_etc_selinux_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_selinux_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_selinux_0_0:ste:1 /etc/sudoers.d - oval:ssg-symlink_file_ownerdirectory_owner_etc_sudoersd_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_sudoersd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_sudoersd_0_0:ste:1 /etc/sysctl.d - oval:ssg-symlink_file_ownerdirectory_owner_etc_sysctld_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_sysctld_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_sysctld_0_0:ste:1 /etc/ipsec.d @@ -225151,10 +248689,16 @@ fi ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_disable_host_auth:obj:1 - oval:ssg-obj_disable_host_auth_sshd_included_files:obj:1 + oval:ssg-obj_disable_host_auth_config_dir:obj:1 @@ -225162,73 +248706,73 @@ fi /sbin/auditctl - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/aureport - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_1:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/ausearch - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_2:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/autrace - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_3:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/auditd - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_4:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/rsyslogd - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_5:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/augenrules - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_6:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/auditctl - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/aureport - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/ausearch - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_2:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/autrace - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_3:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/auditd - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_4:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/rsyslogd - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_5:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/augenrules - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_6:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/auditctl @@ -225270,458 +248814,523 @@ fi /etc/at.allow - oval:ssg-symlink_file_groupowner_at_allow_uid_0:ste:1 - oval:ssg-state_file_groupowner_at_allow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_at_allow_0_0:ste:1 /etc/group- - oval:ssg-symlink_file_groupowner_backup_etc_group_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_group_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_group_0_0:ste:1 /etc/gshadow- - oval:ssg-symlink_file_groupowner_backup_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_gshadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_gshadow_0_0:ste:1 /etc/passwd- - oval:ssg-symlink_file_groupowner_backup_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_passwd_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_passwd_0_0:ste:1 /etc/shadow- - oval:ssg-symlink_file_groupowner_backup_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_shadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_shadow_0_0:ste:1 /etc/cron.allow - oval:ssg-symlink_file_groupowner_cron_allow_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_allow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_allow_0_0:ste:1 /etc/cron.d - oval:ssg-symlink_file_groupowner_cron_d_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_d_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_d_0_0:ste:1 /etc/cron.daily - oval:ssg-symlink_file_groupowner_cron_daily_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_daily_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_daily_0_0:ste:1 /etc/cron.deny - oval:ssg-symlink_file_groupowner_cron_deny_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_deny_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_deny_0_0:ste:1 /etc/cron.hourly - oval:ssg-symlink_file_groupowner_cron_hourly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_hourly_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_hourly_0_0:ste:1 /etc/cron.monthly - oval:ssg-symlink_file_groupowner_cron_monthly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_monthly_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_monthly_0_0:ste:1 /etc/cron.weekly - oval:ssg-symlink_file_groupowner_cron_weekly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_weekly_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_weekly_0_0:ste:1 /etc/crontab - oval:ssg-symlink_file_groupowner_crontab_uid_0:ste:1 - oval:ssg-state_file_groupowner_crontab_gid_0_0:ste:1 - - - /boot/grub2/grub.cfg - oval:ssg-symlink_file_groupowner_efi_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_efi_grub2_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_crontab_0_0:ste:1 /boot/grub2/user.cfg - oval:ssg-symlink_file_groupowner_efi_user_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_efi_user_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_efi_user_cfg_0_0:ste:1 - - /etc/crypttab - oval:ssg-symlink_file_groupowner_etc_crypttab_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_crypttab_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_crypttab_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_crypttab_root_gid_usr:obj:1 + + + + /etc/crypttab + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_crypttab_0_root:ste:1 + /etc/group - oval:ssg-symlink_file_groupowner_etc_group_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_group_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_group_0_0:ste:1 /etc/gshadow - oval:ssg-symlink_file_groupowner_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_gshadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_gshadow_0_0:ste:1 - - /etc/ipsec.conf - oval:ssg-symlink_file_groupowner_etc_ipsec_conf_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_ipsec_conf_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_ipsec_conf_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_ipsec_conf_root_gid_usr:obj:1 + + + + /etc/ipsec.conf + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_ipsec_conf_0_root:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_ipsec_secrets_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_ipsec_secrets_root_gid_usr:obj:1 + + /etc/ipsec.secrets - oval:ssg-symlink_file_groupowner_etc_ipsec_secrets_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_ipsec_secrets_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_ipsec_secrets_0_root:ste:1 - - /etc/group - ^root:\w+:(\w+):.* - 1 - /etc/issue.net - oval:ssg-symlink_file_groupowner_etc_issue_net_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_issue_net_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_issue_net_0_0:ste:1 /etc/passwd - oval:ssg-symlink_file_groupowner_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_passwd_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_passwd_0_0:ste:1 - - /etc/sestatus.conf - oval:ssg-symlink_file_groupowner_etc_sestatus_conf_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_sestatus_conf_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_sestatus_conf_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_sestatus_conf_root_gid_usr:obj:1 + + + + /etc/sestatus.conf + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_sestatus_conf_0_root:ste:1 + /etc/shadow - oval:ssg-symlink_file_groupowner_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_shadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_shadow_0_0:ste:1 /etc/shells - oval:ssg-symlink_file_groupowner_etc_shells_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_shells_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_shells_0_0:ste:1 - - /etc/sudoers - oval:ssg-symlink_file_groupowner_etc_sudoers_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_sudoers_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_sudoers_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_sudoers_root_gid_usr:obj:1 + + + + /etc/sudoers + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_sudoers_0_root:ste:1 + /boot/grub2/grub.cfg - oval:ssg-symlink_file_groupowner_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_grub2_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_grub2_cfg_0_0:ste:1 /etc/ssh/sshd_config - oval:ssg-symlink_file_groupowner_sshd_config_uid_0:ste:1 - oval:ssg-state_file_groupowner_sshd_config_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_sshd_config_0_0:ste:1 - - /boot - ^.*System\.map.*$ - oval:ssg-symlink_file_groupowner_systemmap_uid_root:ste:1 - oval:ssg-state_file_groupowner_systemmap_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_systemmap_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_systemmap_root_gid_usr:obj:1 + + + + /boot + ^.*System\.map.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_systemmap_0_root:ste:1 + /boot/grub2/user.cfg - oval:ssg-symlink_file_groupowner_user_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_user_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_user_cfg_0_0:ste:1 /var/log - oval:ssg-symlink_file_groupowner_var_log_uid_0:ste:1 - oval:ssg-state_file_groupowner_var_log_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_var_log_0_0:ste:1 /var/log/messages - oval:ssg-symlink_file_groupowner_var_log_messages_uid_0:ste:1 - oval:ssg-state_file_groupowner_var_log_messages_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_var_log_messages_0_0:ste:1 /var/log/syslog - oval:ssg-symlink_file_groupowner_var_log_syslog_uid_4:ste:1 - oval:ssg-state_file_groupowner_var_log_syslog_gid_4_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_var_log_syslog_0_4:ste:1 /etc/audit ^.*audit(\.rules|d\.conf)$ - oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_groupownership_audit_configuration_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_audit_configuration_0_0:ste:1 /etc/audit/rules.d ^.*\.rules$ - oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_groupownership_audit_configuration_gid_0_1:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_audit_configuration_0_0:ste:1 - - /etc/ssh - ^.*_key$ - oval:ssg-symlink_file_groupownership_sshd_private_key_uid_ssh_keys:ste:1 - oval:ssg-state_file_groupownership_sshd_private_key_gid_ssh_keys_0:ste:1 - - + /etc/group ^ssh_keys:\w+:(\w+):.* 1 + + /usr/lib/group + ^ssh_keys:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownership_sshd_private_key_ssh_keys_gid_etc:obj:1 + oval:ssg-object_file_groupownership_sshd_private_key_ssh_keys_gid_usr:obj:1 + + + + /etc/ssh + ^.*_key$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_sshd_private_key_0_ssh_keys:ste:1 + /etc/ssh ^.*\.pub$ - oval:ssg-symlink_file_groupownership_sshd_pub_key_uid_0:ste:1 - oval:ssg-state_file_groupownership_sshd_pub_key_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_sshd_pub_key_0_0:ste:1 /etc/group- - oval:ssg-symlink_file_owner_backup_etc_group_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_group_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_group_0_0:ste:1 /etc/gshadow- - oval:ssg-symlink_file_owner_backup_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_gshadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_gshadow_0_0:ste:1 /etc/passwd- - oval:ssg-symlink_file_owner_backup_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_passwd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_passwd_0_0:ste:1 /etc/shadow- - oval:ssg-symlink_file_owner_backup_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_shadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_shadow_0_0:ste:1 /etc/cron.allow - oval:ssg-symlink_file_owner_cron_allow_uid_0:ste:1 - oval:ssg-state_file_owner_cron_allow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_allow_0_0:ste:1 /etc/cron.d - oval:ssg-symlink_file_owner_cron_d_uid_0:ste:1 - oval:ssg-state_file_owner_cron_d_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_d_0_0:ste:1 /etc/cron.daily - oval:ssg-symlink_file_owner_cron_daily_uid_0:ste:1 - oval:ssg-state_file_owner_cron_daily_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_daily_0_0:ste:1 /etc/cron.deny - oval:ssg-symlink_file_owner_cron_deny_uid_0:ste:1 - oval:ssg-state_file_owner_cron_deny_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_deny_0_0:ste:1 /etc/cron.hourly - oval:ssg-symlink_file_owner_cron_hourly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_hourly_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_hourly_0_0:ste:1 /etc/cron.monthly - oval:ssg-symlink_file_owner_cron_monthly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_monthly_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_monthly_0_0:ste:1 /etc/cron.weekly - oval:ssg-symlink_file_owner_cron_weekly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_weekly_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_weekly_0_0:ste:1 /etc/crontab - oval:ssg-symlink_file_owner_crontab_uid_0:ste:1 - oval:ssg-state_file_owner_crontab_uid_0_0:ste:1 - - - /boot/grub2/grub.cfg - oval:ssg-symlink_file_owner_efi_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_efi_grub2_cfg_uid_0_0:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-symlink_file_owner_efi_user_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_efi_user_cfg_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_crontab_0_0:ste:1 /etc/chrony.keys - oval:ssg-symlink_file_owner_etc_chrony_keys_uid_0:ste:1 - oval:ssg-state_file_owner_etc_chrony_keys_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_chrony_keys_0_0:ste:1 /etc/crypttab - oval:ssg-symlink_file_owner_etc_crypttab_uid_0:ste:1 - oval:ssg-state_file_owner_etc_crypttab_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_crypttab_0_0:ste:1 /etc/group - oval:ssg-symlink_file_owner_etc_group_uid_0:ste:1 - oval:ssg-state_file_owner_etc_group_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_group_0_0:ste:1 /etc/gshadow - oval:ssg-symlink_file_owner_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_owner_etc_gshadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_gshadow_0_0:ste:1 /etc/ipsec.conf - oval:ssg-symlink_file_owner_etc_ipsec_conf_uid_0:ste:1 - oval:ssg-state_file_owner_etc_ipsec_conf_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_ipsec_conf_0_0:ste:1 /etc/ipsec.secrets - oval:ssg-symlink_file_owner_etc_ipsec_secrets_uid_0:ste:1 - oval:ssg-state_file_owner_etc_ipsec_secrets_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_ipsec_secrets_0_0:ste:1 /etc/issue.net - oval:ssg-symlink_file_owner_etc_issue_net_uid_0:ste:1 - oval:ssg-state_file_owner_etc_issue_net_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_issue_net_0_0:ste:1 /etc/passwd - oval:ssg-symlink_file_owner_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_owner_etc_passwd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_passwd_0_0:ste:1 /etc/sestatus.conf - oval:ssg-symlink_file_owner_etc_sestatus_conf_uid_0:ste:1 - oval:ssg-state_file_owner_etc_sestatus_conf_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_sestatus_conf_0_0:ste:1 /etc/shadow - oval:ssg-symlink_file_owner_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_owner_etc_shadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_shadow_0_0:ste:1 /etc/shells - oval:ssg-symlink_file_owner_etc_shells_uid_0:ste:1 - oval:ssg-state_file_owner_etc_shells_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_shells_0_0:ste:1 /etc/sudoers - oval:ssg-symlink_file_owner_etc_sudoers_uid_0:ste:1 - oval:ssg-state_file_owner_etc_sudoers_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_sudoers_0_0:ste:1 /boot/grub2/grub.cfg - oval:ssg-symlink_file_owner_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_grub2_cfg_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_grub2_cfg_0_0:ste:1 /etc/ssh/sshd_config - oval:ssg-symlink_file_owner_sshd_config_uid_0:ste:1 - oval:ssg-state_file_owner_sshd_config_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_sshd_config_0_0:ste:1 /boot ^.*System\.map.*$ - oval:ssg-symlink_file_owner_systemmap_uid_0:ste:1 - oval:ssg-state_file_owner_systemmap_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_systemmap_0_0:ste:1 /boot/grub2/user.cfg - oval:ssg-symlink_file_owner_user_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_user_cfg_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_user_cfg_0_0:ste:1 /var/log - oval:ssg-symlink_file_owner_var_log_uid_0:ste:1 - oval:ssg-state_file_owner_var_log_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_var_log_0_0:ste:1 /var/log/messages - oval:ssg-symlink_file_owner_var_log_messages_uid_0:ste:1 - oval:ssg-state_file_owner_var_log_messages_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_var_log_messages_0_0:ste:1 + + syslog + /var/log/syslog - oval:ssg-symlink_file_owner_var_log_syslog_uid_104:ste:1 - oval:ssg-state_file_owner_var_log_syslog_uid_104_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_var_log_syslog_0_syslog:ste:1 /etc/audit ^.*audit(\.rules|d\.conf)$ - oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_ownership_audit_configuration_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_audit_configuration_0_0:ste:1 /etc/audit/rules.d ^.*\.rules$ - oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_ownership_audit_configuration_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_audit_configuration_0_0:ste:1 /lib - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_0:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /lib64 - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_1:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /usr/lib - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_2:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /usr/lib64 - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_3:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /etc/ssh ^.*_key$ - oval:ssg-symlink_file_ownership_sshd_private_key_uid_0:ste:1 - oval:ssg-state_file_ownership_sshd_private_key_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_sshd_private_key_0_0:ste:1 /etc/ssh ^.*\.pub$ - oval:ssg-symlink_file_ownership_sshd_pub_key_uid_0:ste:1 - oval:ssg-state_file_ownership_sshd_pub_key_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_sshd_pub_key_0_0:ste:1 /etc/at.allow @@ -225800,16 +249409,6 @@ fi oval:ssg-exclude_symlinks__crontab:ste:1 oval:ssg-state_file_permissions_crontab_0_mode_0600or_stricter_:ste:1 - - /boot/grub2/grub.cfg - oval:ssg-exclude_symlinks__efi_grub2_cfg:ste:1 - oval:ssg-state_file_permissions_efi_grub2_cfg_0_mode_0700or_stricter_:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-exclude_symlinks__efi_user_cfg:ste:1 - oval:ssg-state_file_permissions_efi_user_cfg_0_mode_0700or_stricter_:ste:1 - /etc/audit/auditd.conf oval:ssg-exclude_symlinks__etc_audit_auditd:ste:1 @@ -225889,28 +249488,28 @@ fi /lib - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_0_mode_7755or_stricter_:ste:1 /lib64 - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_1_mode_7755or_stricter_:ste:1 /usr/lib - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_2_mode_7755or_stricter_:ste:1 /usr/lib64 - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 @@ -225950,7 +249549,7 @@ fi /var/log/messages oval:ssg-exclude_symlinks__var_log_messages:ste:1 - oval:ssg-state_file_permissions_var_log_messages_0_mode_0600or_stricter_:ste:1 + oval:ssg-state_file_permissions_var_log_messages_0_mode_0640or_stricter_:ste:1 /var/log/syslog @@ -227318,14 +250917,17 @@ fi - - /home - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/home[\s]+[\S]+[\s]+([\S]+) + + /etc/passwd + 1 + + / + + + + /etc/passwd @@ -227545,6 +251147,20 @@ fi ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) 1 + + /etc/NetworkManager/NetworkManager.conf + ^\s*\[main\].*(?:\n\s*[^[\s].*)*\n^[ \t]*dns\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/NetworkManager/conf.d + .*\.conf$ + ^\s*\[main\].*(?:\n\s*[^[\s].*)*\n^[ \t]*dns\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/NetworkManager/NetworkManager.conf + aide @@ -227671,12 +251287,6 @@ fi rng-tools - - rsh-server - - - rsh - rsyslog-gnutls @@ -227713,12 +251323,6 @@ fi syslog-ng - - talk-server - - - talk - telnet-server @@ -227746,9 +251350,6 @@ fi vsftpd - - xorg-x11-server-common - /dev/shm @@ -227776,30 +251377,30 @@ fi /lib - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_0:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /lib64 - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_1:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /usr/lib - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_2:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /usr/lib64 - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_3:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /etc/rsyslog.conf @@ -227922,6 +251523,14 @@ fi ssh_sysadm_login + + /etc/selinux/config + ^SELINUXTYPE=(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/selinux/config + ^atd\.(service|socket)$ ActiveState @@ -228308,10 +251917,16 @@ fi ^[ \t]*(?i)Protocol(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Protocol(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_allow_only_protocol2:obj:1 - oval:ssg-obj_sshd_allow_only_protocol2_sshd_included_files:obj:1 + oval:ssg-obj_sshd_allow_only_protocol2_config_dir:obj:1 @@ -228329,10 +251944,16 @@ fi ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_compression:obj:1 - oval:ssg-obj_sshd_disable_compression_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_compression_config_dir:obj:1 @@ -228350,10 +251971,16 @@ fi ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_empty_passwords:obj:1 - oval:ssg-obj_sshd_disable_empty_passwords_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_empty_passwords_config_dir:obj:1 @@ -228371,10 +251998,16 @@ fi ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_gssapi_auth:obj:1 - oval:ssg-obj_sshd_disable_gssapi_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_gssapi_auth_config_dir:obj:1 @@ -228392,10 +252025,16 @@ fi ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_kerb_auth:obj:1 - oval:ssg-obj_sshd_disable_kerb_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_kerb_auth_config_dir:obj:1 @@ -228413,10 +252052,16 @@ fi ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_pubkey_auth:obj:1 - oval:ssg-obj_sshd_disable_pubkey_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_pubkey_auth_config_dir:obj:1 @@ -228434,10 +252079,16 @@ fi ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_rhosts:obj:1 - oval:ssg-obj_sshd_disable_rhosts_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_rhosts_config_dir:obj:1 @@ -228455,10 +252106,16 @@ fi ^[ \t]*(?i)RhostsRSAAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)RhostsRSAAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_rhosts_rsa:obj:1 - oval:ssg-obj_sshd_disable_rhosts_rsa_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_rhosts_rsa_config_dir:obj:1 @@ -228476,10 +252133,16 @@ fi ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_root_login:obj:1 - oval:ssg-obj_sshd_disable_root_login_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_root_login_config_dir:obj:1 @@ -228497,10 +252160,16 @@ fi ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_root_password_login:obj:1 - oval:ssg-obj_sshd_disable_root_password_login_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_root_password_login_config_dir:obj:1 @@ -228518,10 +252187,16 @@ fi ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_tcp_forwarding:obj:1 - oval:ssg-obj_sshd_disable_tcp_forwarding_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_tcp_forwarding_config_dir:obj:1 @@ -228539,10 +252214,16 @@ fi ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_user_known_hosts:obj:1 - oval:ssg-obj_sshd_disable_user_known_hosts_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_user_known_hosts_config_dir:obj:1 @@ -228560,10 +252241,16 @@ fi ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_x11_forwarding:obj:1 - oval:ssg-obj_sshd_disable_x11_forwarding_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_x11_forwarding_config_dir:obj:1 @@ -228581,10 +252268,16 @@ fi ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_do_not_permit_user_env:obj:1 - oval:ssg-obj_sshd_do_not_permit_user_env_sshd_included_files:obj:1 + oval:ssg-obj_sshd_do_not_permit_user_env_config_dir:obj:1 @@ -228602,10 +252295,16 @@ fi ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_gssapi_auth:obj:1 - oval:ssg-obj_sshd_enable_gssapi_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_gssapi_auth_config_dir:obj:1 @@ -228623,10 +252322,16 @@ fi ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_pam:obj:1 - oval:ssg-obj_sshd_enable_pam_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_pam_config_dir:obj:1 @@ -228644,10 +252349,16 @@ fi ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_pubkey_auth:obj:1 - oval:ssg-obj_sshd_enable_pubkey_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_pubkey_auth_config_dir:obj:1 @@ -228665,10 +252376,16 @@ fi ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_strictmodes:obj:1 - oval:ssg-obj_sshd_enable_strictmodes_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_strictmodes_config_dir:obj:1 @@ -228686,10 +252403,16 @@ fi ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_warning_banner:obj:1 - oval:ssg-obj_sshd_enable_warning_banner_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_warning_banner_config_dir:obj:1 @@ -228707,10 +252430,16 @@ fi ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_warning_banner_net:obj:1 - oval:ssg-obj_sshd_enable_warning_banner_net_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_warning_banner_net_config_dir:obj:1 @@ -228728,10 +252457,16 @@ fi ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_x11_forwarding:obj:1 - oval:ssg-obj_sshd_enable_x11_forwarding_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_x11_forwarding_config_dir:obj:1 @@ -228754,10 +252489,16 @@ fi ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_print_last_log:obj:1 - oval:ssg-obj_sshd_print_last_log_sshd_included_files:obj:1 + oval:ssg-obj_sshd_print_last_log_config_dir:obj:1 @@ -228775,10 +252516,16 @@ fi ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_keepalive:obj:1 - oval:ssg-obj_sshd_set_keepalive_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_keepalive_config_dir:obj:1 @@ -228796,10 +252543,16 @@ fi ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_keepalive_0:obj:1 - oval:ssg-obj_sshd_set_keepalive_0_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_keepalive_0_config_dir:obj:1 @@ -228817,10 +252570,16 @@ fi ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_loglevel_info:obj:1 - oval:ssg-obj_sshd_set_loglevel_info_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_loglevel_info_config_dir:obj:1 @@ -228838,10 +252597,16 @@ fi ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_loglevel_verbose:obj:1 - oval:ssg-obj_sshd_set_loglevel_verbose_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_loglevel_verbose_config_dir:obj:1 @@ -228859,10 +252624,16 @@ fi ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_use_priv_separation:obj:1 - oval:ssg-obj_sshd_use_priv_separation_sshd_included_files:obj:1 + oval:ssg-obj_sshd_use_priv_separation_config_dir:obj:1 @@ -228880,10 +252651,16 @@ fi ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_x11_use_localhost:obj:1 - oval:ssg-obj_sshd_x11_use_localhost_sshd_included_files:obj:1 + oval:ssg-obj_sshd_x11_use_localhost_config_dir:obj:1 @@ -228893,22 +252670,22 @@ fi ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\bnoexec.*$ + ^[\s]*Defaults\b[^!\n]*\bnoexec.*$ 1 ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\brequiretty.*$ + ^[\s]*Defaults\b[^!\n]*\brequiretty.*$ 1 ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\buse_pty.*$ + ^[\s]*Defaults\b[^!\n]*\buse_pty.*$ 1 ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$ + ^[\s]*Defaults\b[^!\n]*\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$ 1 @@ -232852,42 +256629,42 @@ fi ^(ExecStartPost=\-\/sbin\/augenrules.*$|Requires=augenrules.service) 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -232919,6 +256696,12 @@ fi openshift-kubelet + + /run/ostree-booted + + + /ostree + /etc/default/grub ^\s*GRUB_DISABLE_RECOVERY=(.*)$ @@ -232929,6 +256712,14 @@ fi ^([\s]*server[\s]+.+$){2,}$ 1 + + /etc/almalinux-release + + + /etc/almalinux-release + ^AlmaLinux release 9.[0-9]+ .*$ + 1 + oraclelinux-release @@ -232939,14 +256730,13 @@ fi oraclelinux-release - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)\.\d+"$ + + + redhat-release + + + /etc/redhat-release + ^Red Hat Enterprise Linux release (\d)\.\d+$ 1 @@ -232996,6 +256786,16 @@ fi SLE_HPC-release + + + SLES-release + + + SLES_SAP-release + + + sle-ha-release + SUSE-MicroOS-release @@ -233003,6 +256803,10 @@ fi SLE-Micro-release + + + SL-Micro-release + /etc/lsb-release @@ -233011,19 +256815,9 @@ fi ^DISTRIB_ID=Ubuntu$ 1 - + /etc/lsb-release - ^DISTRIB_CODENAME=xenial$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=bionic$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=focal$ + ^DISTRIB_CODENAME=noble$ 1 @@ -233074,15 +256868,6 @@ fi 0 - - true - true - true - true - true - true - true - true true @@ -233187,6 +256972,9 @@ fi + + + @@ -233256,8 +257044,8 @@ fi - - + + \s*ExecStart\s*=\s*\S+\s+-s\s+\S+.* symbolic link @@ -233271,7 +257059,6 @@ fi false false false - false false false false @@ -233335,9 +257122,6 @@ fi - - - @@ -233365,9 +257149,6 @@ fi (?i)true - - ^LinuxAudit$ - /etc/systemd/system/default.target ^(/usr)?/lib/systemd/system/multi-user.target$ @@ -233419,12 +257200,6 @@ fi /var/run/faillock - - 2 - - - 2 - @@ -233475,13 +257250,13 @@ fi - + 0 - + 0 @@ -233627,6 +257402,9 @@ fi + + 1 + ^(nobody|nfsnobody)$ @@ -233643,7 +257421,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ regular @@ -233665,7 +257443,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ ^\/[^\/\n]*\/[^\/\n]{1,}.*$ @@ -233735,7 +257513,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ ^(nobody|nfsnobody)$ @@ -233757,7 +257535,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ directory @@ -233848,9 +257626,6 @@ fi UP - - ^.*\bdefault|none\b.*$ - 0 true @@ -233944,6 +257719,9 @@ fi 1000 + + symbolic link + 0 @@ -233956,6 +257734,7 @@ fi ^/dev/.*$ + ^(?!afs$|autofs$|ceph$|cifs$|smb3$|smbfs$|sshfs$|ncpfs$|ncp$|nfs$|nfs4$|gfs$|gfs2$|glusterfs$|gpfs$|pvfs2$|ocfs2$|lustre$|davfs$|fuse\.sshfs$).+ nodev @@ -233977,18 +257756,6 @@ fi - - ^(?i)0(?-i)$ - - - ^(?i)0(?-i)$ - - - ^(?i)none(?-i)$ - - - ^(?i)none(?-i)$ - 0 @@ -234010,9 +257777,6 @@ fi ^(enforcing|permissive)$ - - - @@ -234025,6 +257789,16 @@ fi ^(x86_64|aarch64|ppc64le|s390x|.*-amd64)$ + + + + + bind + + + .+ + iso9660 + @@ -234034,6 +257808,9 @@ fi + + 0 + @@ -234083,7 +257860,7 @@ fi - + fips @@ -234092,8 +257869,44 @@ fi ^(?:.*\s)?fips=1(?:\s.*)?$ - ^FIPS(:OSPP)?$ + ^FIPS(:(OSPP|STIG))?$ + + /usr/share/crypto-policies/FIPS/bind.txt + + + /usr/share/crypto-policies/FIPS/gnutls.txt + + + /usr/share/crypto-policies/FIPS/java.txt + + + /usr/share/crypto-policies/FIPS/javasystem.txt + + + /usr/share/crypto-policies/FIPS/krb5.txt + + + /usr/share/crypto-policies/FIPS/libreswan.txt + + + /usr/share/crypto-policies/FIPS/libssh.txt + + + /usr/share/crypto-policies/FIPS/openssh.txt + + + /usr/share/crypto-policies/FIPS/opensshserver.txt + + + /usr/share/crypto-policies/FIPS/opensslcnf.txt + + + /usr/share/crypto-policies/FIPS/openssl.txt + + + /usr/share/crypto-policies/FIPS/openssl_fips.txt + 1 @@ -234109,6 +257922,17 @@ fi ^.*xattrs.*$ + + fail + fail + fail + fail + fail + fail + fail + fail + fail + fail false @@ -234130,6 +257954,9 @@ fi ^security$ + + ^(0|[Ff]alse|[Nn]o)$ + 629e59ec 8d8b756f @@ -234168,6 +257995,12 @@ fi + + + + + 0 + @@ -234309,6 +258142,9 @@ fi ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -234441,7 +258277,7 @@ fi - ^(?i)50(?-i)$ + ^(?i)yes(?-i)$ @@ -234452,59 +258288,38 @@ fi ^(?i)yes(?-i)$ + + ^LinuxAudit$ + + + ^0$ + + + ^0$ + + + ^none$ + + + ^none$ + ^'lock-screen'$ - - 0 + + - - 0 - - - 0 - - - 0 - - + symbolic link - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - + symbolic link - - 0 + + - - 0 - - - 0 - - - 0 - - - symbolic link + + false @@ -234570,77 +258385,41 @@ fi symbolic link - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link + + false @@ -234722,53 +258501,14 @@ fi ^no$ - - 0 + + ^no$ + + + - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link + + false @@ -234822,458 +258562,215 @@ fi symbolic link - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 4 + + - - symbolic link + + - - 0 + + - - 0 + + - - symbolic link + + - - - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 104 - - - symbolic link - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link + + false @@ -235473,34 +258970,6 @@ fi symbolic link - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - false false @@ -235818,12 +259287,11 @@ fi symbolic link - + false false false false - false false false false @@ -235860,7 +259328,7 @@ fi .*rescue\.conf$ - ^(?:.*\s)?audit_backlog_limit=8192(?:\s.*)?$ + .*rescue\.conf$ @@ -236409,13 +259877,9 @@ fi grpquota - - nodev + + nodev - - 1 - nodev - noexec @@ -236574,20 +260038,14 @@ fi 1 nosuid - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link + + ^none|default$ + + + ^none|default$ + + + (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) @@ -236673,12 +260131,18 @@ fi + + + inactive|failed masked + + not-found + auditd.service @@ -236694,12 +260158,18 @@ fi masked + + not-found + inactive|failed masked + + not-found + chronyd.service @@ -236724,6 +260194,9 @@ fi masked + + not-found + fapolicyd.service @@ -236757,18 +260230,27 @@ fi masked + + not-found + inactive|failed masked + + not-found + inactive|failed masked + + not-found + pcscd.service @@ -236793,12 +260275,18 @@ fi masked + + not-found + inactive|failed masked + + not-found + rngd.service @@ -236814,6 +260302,9 @@ fi masked + + not-found + rsyslog.service @@ -236829,18 +260320,27 @@ fi masked + + not-found + inactive|failed masked + + not-found + inactive|failed masked + + not-found + sshd.service @@ -236886,6 +260386,9 @@ fi masked + + not-found + ufw.service @@ -236910,11 +260413,17 @@ fi ^2$ + + ^2$ + - + - + + + + ^no$ @@ -236922,125 +260431,188 @@ fi ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^yes$ ^yes$ + + ^yes$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^prohibit-password$ ^prohibit-password$ + + ^prohibit-password$ + ^no$ ^no$ + + ^no$ + ^yes$ ^yes$ + + ^yes$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + ^/etc/issue$ ^/etc/issue$ + + ^/etc/issue$ + ^/etc/issue.net$ ^/etc/issue.net$ + + ^/etc/issue.net$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + - + - + + + + ^0$ @@ -237048,23 +260620,35 @@ fi ^0$ + + ^0$ + ^INFO$ ^INFO$ + + ^INFO$ + ^VERBOSE$ ^VERBOSE$ + + ^VERBOSE$ + - + - + + + + ^yes$ @@ -237072,6 +260656,9 @@ fi ^yes$ + + ^yes$ + @@ -237273,17 +260860,11 @@ fi 0 - - 1 + + - - 2 - - - 1 - - - 2 + + @@ -237537,6 +261118,10 @@ fi active + + /ostree + symbolic link + ^(true|"true")$ @@ -237552,11 +261137,14 @@ fi unix - - rhcos - - - 4 + + unix + + + ^10.*$ + + + 10 unix @@ -237609,6 +261197,18 @@ fi ^15.*$ + + unix + + + ^16.*$ + + + ^16.*$ + + + ^16.*$ + unix @@ -237618,6 +261218,12 @@ fi ^5.*$ + + unix + + + ^6.*$ + 1 @@ -237651,9 +261257,6 @@ fi - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - @@ -237726,6 +261329,7 @@ fi + @@ -237773,7 +261377,6 @@ fi - @@ -237813,6 +261416,18 @@ fi + + + ^(/etc/ssh/(?!/))? + + + + + + + + + @@ -237835,17 +261450,6 @@ fi - - - - - - - - - - - @@ -237882,10 +261486,10 @@ fi - + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - + ^\s*remember\s*=\s*([0-9]+) @@ -237900,20 +261504,20 @@ fi - + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - + ^\s*remember\s*=\s*([0-9]+) ^\s*password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so.*$ - + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - + ^\s*remember\s*=\s*([0-9]+) @@ -237922,12 +261526,6 @@ fi ^[\s]*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*even_deny_root @@ -237950,24 +261548,6 @@ fi - - - - - - - - - - - - - - - - - - @@ -238014,6 +261594,7 @@ fi + @@ -238126,7 +261707,9 @@ fi - + + + @@ -238201,7 +261784,9 @@ fi - + + + @@ -238251,7 +261836,9 @@ fi - + + + @@ -238478,8 +262065,13 @@ fi - + + + /dev/mapper/ + + + @@ -238517,12 +262109,6 @@ fi - - - -oMACs= - - - @@ -238551,12 +262137,6 @@ fi ^\s*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*deny=([0-9]+) @@ -238567,12 +262147,6 @@ fi ^\s*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*fail_interval=([0-9]+) @@ -238580,44 +262154,101 @@ fi ^[\s]*fail_interval[\s]*=[\s]*([0-9]+) - ^\s*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*unlock_time=([0-9]+) ^[\s]*unlock_time[\s]*=[\s]*([0-9]+) - + + + + ^\-w[\s]+ + \/etc\/cron.d\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + ^\-w[\s]+ [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - - + + ^\-w[\s]+ \/var\/log\/lastlog [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - + ^\-w[\s]+ \/var\/log\/tallylog [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + ^\-w[\s]+ + \/etc\/selinux\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/usr\/share\/selinux\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/log\/btmp + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/run\/utmp + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/log\/wtmp + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/sudoers + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/sudoers.d\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/localtime + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+creat[\s]+|([\s]+|[,])creat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* @@ -238840,30 +262471,100 @@ fi - + + + ^\-w[\s]+ + \/etc\/group + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/gshadow + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/security\/opasswd + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/passwd + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/shadow + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/spool\/cron + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + ^\-w[\s]+ \/var\/log\/sudo.log [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - - + + + 0 - - + + 0 - - + + 0 - - + + - - + + - - + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 @@ -238877,27 +262578,230 @@ fi - - + + 0 - - + + 0 - - + + 0 - - + + 0 - - + + 0 - - + + 0 - - + + 0 + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + ^(?:.*\s)?audit_backlog_limit= + + (?:\s.*)?$ + + + ^(?:.*\s)?l1tf= @@ -239993,6 +263897,16 @@ fi + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( + + ).*?:.* + + + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( @@ -240084,6 +263998,9 @@ fi [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + 0 + @@ -240149,6 +264066,7 @@ fi + ^(/etc/ssh/(?!/))? @@ -240161,9 +264079,6 @@ fi - - - @@ -240417,9 +264332,6 @@ fi - - - @@ -240469,9 +264381,6 @@ fi - - - @@ -240504,6 +264413,7 @@ fi + @@ -240582,3644 +264492,19 @@ fi - + build_shorthand.py from SCAP Security Guide - ssg: 0.1.76 + ssg: 0.1.79 2.0 - 2025-05-06T00:00:00 + 2025-12-16T00:00:00 - - Ensure gpgcheck Enabled In Main yum Configuration + + Set Account Expiration Following Inactivity in password-auth - ocil:ssg-ensure_gpgcheck_globally_activated_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - - ocil:ssg-audit_rules_privileged_commands_unix_chkpwd_action:testaction:1 - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_log_martians_action:testaction:1 - - - - Verify Permissions On /etc/nftables Directory - - ocil:ssg-directory_permissions_etc_nftables_action:testaction:1 - - - - All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive - - ocil:ssg-accounts_users_home_files_permissions_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg User Ownership - - ocil:ssg-file_owner_grub2_cfg_action:testaction:1 - - - - Configure the confidence in TPM for entropy - - ocil:ssg-grub2_rng_core_default_quality_argument_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly in login.defs - - ocil:ssg-accounts_umask_etc_login_defs_action:testaction:1 - - - - Uninstall talk-server Package - - ocil:ssg-package_talk-server_removed_action:testaction:1 - - - - Disable vsyscall emulate execution only - - ocil:ssg-kernel_config_legacy_vsyscall_xonly_action:testaction:1 - - - - Disable RDS Support - - ocil:ssg-kernel_module_rds_disabled_action:testaction:1 - - - - Configure System to Forward All Mail through a specific host - - ocil:ssg-postfix_client_configure_relayhost_action:testaction:1 - - - - Verify Group Who Owns cron.monthly - - ocil:ssg-file_groupowner_cron_monthly_action:testaction:1 - - - - Ensure tftp Daemon Uses Secure Mode - - ocil:ssg-tftpd_uses_secure_mode_action:testaction:1 - - - - Ensure '/etc/system-fips' exists - - ocil:ssg-etc_system_fips_exists_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lchown - - ocil:ssg-audit_rules_dac_modification_lchown_action:testaction:1 - - - - Uninstall squid Package - - ocil:ssg-package_squid_removed_action:testaction:1 - - - - Disable vsyscalls - - ocil:ssg-grub2_vsyscall_argument_action:testaction:1 - - - - Sign kernel modules with SHA-512 - - ocil:ssg-kernel_config_module_sig_sha512_action:testaction:1 - - - - Disable IPv6 Addressing on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_disable_ipv6_action:testaction:1 - - - - Configure SSSD LDAP Backend to Use TLS For All Transactions - - ocil:ssg-sssd_ldap_start_tls_action:testaction:1 - - - - Add noexec Option to Removable Media Partitions - - ocil:ssg-mount_option_noexec_removable_partitions_action:testaction:1 - - - - Verify Group Who Owns /etc/sysctl.d Directory - - ocil:ssg-directory_groupowner_etc_sysctld_action:testaction:1 - - - - Verify Group Who Owns /etc/sudoers File - - ocil:ssg-file_groupowner_etc_sudoers_action:testaction:1 - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_redirects_action:testaction:1 - - - - Set Password Hashing Algorithm in /etc/libuser.conf - - ocil:ssg-set_password_hashing_algorithm_libuserconf_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - - ocil:ssg-sysctl_fs_protected_symlinks_action:testaction:1 - - - - Verify Permissions On /etc/ipsec.d Directory - - ocil:ssg-directory_permissions_etc_ipsecd_action:testaction:1 - - - - Ensure that System Accounts Do Not Run a Shell Upon Login - - ocil:ssg-no_shelllogin_for_systemaccounts_action:testaction:1 - - - - Add nodev Option to /var/log - - ocil:ssg-mount_option_var_log_nodev_action:testaction:1 - - - - Ensure cron Is Logging To Rsyslog - - ocil:ssg-rsyslog_cron_logging_action:testaction:1 - - - - Install dnf-automatic Package - - ocil:ssg-package_dnf-automatic_installed_action:testaction:1 - - - - Limit the Number of Concurrent Login Sessions Allowed Per User - - ocil:ssg-accounts_max_concurrent_login_sessions_action:testaction:1 - - - - Ensure yum Removes Previous Package Versions - - ocil:ssg-clean_components_post_updating_action:testaction:1 - - - - Uninstall DHCP Server Package - - ocil:ssg-package_dhcp_removed_action:testaction:1 - - - - Verify Permissions on System.map Files - - ocil:ssg-file_permissions_systemmap_action:testaction:1 - - - - Enable use of Berkeley Packet Filter with seccomp - - ocil:ssg-kernel_config_seccomp_filter_action:testaction:1 - - - - Require Authentication for Emergency Systemd Target - - ocil:ssg-require_emergency_target_auth_action:testaction:1 - - - - Set SSH Client Alive Count Max - - ocil:ssg-sshd_set_keepalive_action:testaction:1 - - - - Add nodev Option to Non-Root Local Partitions - - ocil:ssg-mount_option_nodev_nonroot_local_partitions_action:testaction:1 - - - - User Initialization Files Must Not Run World-Writable Programs - - ocil:ssg-accounts_user_dot_no_world_writable_programs_action:testaction:1 - - - - All Interactive Users Must Have A Home Directory Defined - - ocil:ssg-accounts_user_interactive_home_directory_defined_action:testaction:1 - - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_action:testaction:1 - - - - Add nodev Option to /tmp - - ocil:ssg-mount_option_tmp_nodev_action:testaction:1 - - - - Uninstall rsh Package - - ocil:ssg-package_rsh_removed_action:testaction:1 - - - - Add nosuid Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_nosuid_action:testaction:1 - - - - Verify the SSH Private Key Files Have a Passcode - - ocil:ssg-ssh_keys_passphrase_protected_action:testaction:1 - - - - Ensure SELinux is Not Disabled - - ocil:ssg-selinux_not_disabled_action:testaction:1 - - - - Install the cron service - - ocil:ssg-package_cron_installed_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Different Characters - - ocil:ssg-accounts_password_pam_difok_action:testaction:1 - - - - Enable seccomp to safely compute untrusted bytecode - - ocil:ssg-kernel_config_seccomp_action:testaction:1 - - - - Require Credential Prompting for Remote Access in GNOME3 - - ocil:ssg-dconf_gnome_remote_access_credential_prompt_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Group Ownership - - ocil:ssg-file_groupowner_user_cfg_action:testaction:1 - - - - Verify that Shared Library Directories Have Root Ownership - - ocil:ssg-dir_ownership_library_dirs_action:testaction:1 - - - - Verify the system-wide library files in directories -"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. - - ocil:ssg-root_permissions_syslibrary_files_action:testaction:1 - - - - Enable ExecShield via sysctl - - ocil:ssg-sysctl_kernel_exec_shield_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/shadow - - ocil:ssg-audit_rules_usergroup_modification_shadow_action:testaction:1 - - - - All User Files and Directories In The Home Directory Must Have a Valid Owner - - ocil:ssg-accounts_users_home_files_ownership_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - - ocil:ssg-accounts_password_pam_lcredit_action:testaction:1 - - - - The Chronyd service is enabled - - ocil:ssg-service_chronyd_enabled_action:testaction:1 - - - - Install firewalld Package - - ocil:ssg-package_firewalld_installed_action:testaction:1 - - - - Verify Permissions On /etc/sudoers.d Directory - - ocil:ssg-directory_permissions_etc_sudoersd_action:testaction:1 - - - - Set GNOME3 Screensaver Inactivity Timeout - - ocil:ssg-dconf_gnome_screensaver_idle_delay_action:testaction:1 - - - - Record Events that Modify User/Group Information - - ocil:ssg-audit_rules_usergroup_modification_action:testaction:1 - - - - Verify Permissions on SSH Server config file - - ocil:ssg-file_permissions_sshd_config_action:testaction:1 - - - - Ensure Authentication Required for Single User Mode - - ocil:ssg-ensure_root_password_configured_action:testaction:1 - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon - - ocil:ssg-usbguard_allow_hid_and_hub_action:testaction:1 - - - - Ensure /tmp Located On Separate Partition - - ocil:ssg-partition_for_tmp_action:testaction:1 - - - - Enable the OpenSSH Service - - ocil:ssg-service_sshd_enabled_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg Permissions - - ocil:ssg-file_permissions_grub2_cfg_action:testaction:1 - - - - Enable SSH Warning Banner - - ocil:ssg-sshd_enable_warning_banner_net_action:testaction:1 - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses_action:testaction:1 - - - - Configure auditing of successful permission changes - - ocil:ssg-audit_perm_change_success_action:testaction:1 - - - - Disable Bluetooth Kernel Module - - ocil:ssg-kernel_module_bluetooth_disabled_action:testaction:1 - - - - Install libselinux Package - - ocil:ssg-package_libselinux_installed_action:testaction:1 - - - - Verify User Who Owns gshadow File - - ocil:ssg-file_owner_etc_gshadow_action:testaction:1 - - - - Uninstall net-snmp Package - - ocil:ssg-package_net-snmp_removed_action:testaction:1 - - - - Remove ftp Package - - ocil:ssg-package_ftp_removed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - - ocil:ssg-audit_privileged_commands_poweroff_action:testaction:1 - - - - Restrict unprivileged access to the kernel syslog - - ocil:ssg-kernel_config_security_dmesg_restrict_action:testaction:1 - - - - Verify Group Who Owns Backup gshadow File - - ocil:ssg-file_groupowner_backup_etc_gshadow_action:testaction:1 - - - - Verify User Who Owns /var/log/messages File - - ocil:ssg-file_owner_var_log_messages_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - umount2 - - ocil:ssg-audit_rules_dac_modification_umount2_action:testaction:1 - - - - Ensure All Files Are Owned by a Group - - ocil:ssg-file_permissions_ungroupowned_action:testaction:1 - - - - Add nosuid Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_nosuid_action:testaction:1 - - - - Audit Configuration Files Permissions are 640 or More Restrictive - - ocil:ssg-file_permissions_audit_configuration_action:testaction:1 - - - - Verify Permissions on /etc/audit/rules.d/*.rules - - ocil:ssg-file_permissions_etc_audit_rulesd_action:testaction:1 - - - - Ensure a dedicated group owns sudo - - ocil:ssg-sudo_dedicated_group_action:testaction:1 - - - - Ensure /srv Located On Separate Partition - - ocil:ssg-partition_for_srv_action:testaction:1 - - - - Randomize the address of the kernel image (KASLR) - - ocil:ssg-kernel_config_randomize_base_action:testaction:1 - - - - Enable checks on notifier call chains - - ocil:ssg-kernel_config_debug_notifiers_action:testaction:1 - - - - Set Interval For Counting Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_interval_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Different Categories - - ocil:ssg-accounts_password_pam_minclass_action:testaction:1 - - - - Record Events that Modify the System's Network Environment - - ocil:ssg-audit_rules_networkconfig_modification_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Screensaver Settings - - ocil:ssg-dconf_gnome_screensaver_user_locks_action:testaction:1 - - - - Disable the authlogin_nsswitch_use_ldap SELinux Boolean - - ocil:ssg-sebool_authlogin_nsswitch_use_ldap_action:testaction:1 - - - - Make sure that the dconf databases are up-to-date with regards to respective keyfiles - - ocil:ssg-dconf_db_up_to_date_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchmod - - ocil:ssg-audit_rules_dac_modification_fchmod_action:testaction:1 - - - - Verify All Account Password Hashes are Shadowed - - ocil:ssg-accounts_password_all_shadowed_action:testaction:1 - - - - Allow Only SSH Protocol 2 - - ocil:ssg-sshd_allow_only_protocol2_action:testaction:1 - - - - Deactivate Wireless Network Interfaces - - ocil:ssg-wireless_disable_interfaces_action:testaction:1 - - - - Configure auditing of successful file creations - - ocil:ssg-audit_create_success_action:testaction:1 - - - - Install cryptsetup Package - - ocil:ssg-package_cryptsetup-luks_installed_action:testaction:1 - - - - Disable Ctrl-Alt-Del Reboot Activation - - ocil:ssg-disable_ctrlaltdel_reboot_action:testaction:1 - - - - Install the opensc Package For Multifactor Authentication - - ocil:ssg-package_opensc_installed_action:testaction:1 - - - - Only Authorized Local User Accounts Exist on Operating System - - ocil:ssg-accounts_authorized_local_users_action:testaction:1 - - - - Direct root Logins Not Allowed - - ocil:ssg-no_direct_root_logins_action:testaction:1 - - - - Enable GSSAPI Authentication - - ocil:ssg-sshd_enable_gssapi_auth_action:testaction:1 - - - - Audit Configuration Files Must Be Owned By Root - - ocil:ssg-file_ownership_audit_configuration_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - - ocil:ssg-audit_rules_kernel_module_loading_init_action:testaction:1 - - - - Set Existing Passwords Warning Age - - ocil:ssg-accounts_password_set_warn_age_existing_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - chown - - ocil:ssg-audit_rules_dac_modification_chown_action:testaction:1 - - - - Uninstall nfs-utils Package - - ocil:ssg-package_nfs-utils_removed_action:testaction:1 - - - - Verify that system commands directories have root ownership - - ocil:ssg-dir_system_commands_root_owned_action:testaction:1 - - - - Verify User Who Owns group File - - ocil:ssg-file_owner_etc_group_action:testaction:1 - - - - Uninstall cyrus-imapd Package - - ocil:ssg-package_cyrus-imapd_removed_action:testaction:1 - - - - Encrypt Partitions - - ocil:ssg-encrypt_partitions_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - renameat - - ocil:ssg-audit_rules_file_deletion_events_renameat_action:testaction:1 - - - - Add usrquota Option to /home - - ocil:ssg-mount_option_home_usrquota_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usermod - - ocil:ssg-audit_rules_privileged_commands_usermod_action:testaction:1 - - - - Disable the selinuxuser_execstack SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execstack_action:testaction:1 - - - - Ensure SELinux Not Disabled in /etc/default/grub - - ocil:ssg-grub2_enable_selinux_action:testaction:1 - - - - Record Access Events to Audit Log Directory - - ocil:ssg-directory_access_var_log_audit_action:testaction:1 - - - - Disable the uvcvideo module - - ocil:ssg-kernel_module_uvcvideo_disabled_action:testaction:1 - - - - Assign Expiration Date to Temporary Accounts - - ocil:ssg-account_temp_expire_date_action:testaction:1 - - - - Record Events When Privileged Executables Are Run - - ocil:ssg-audit_rules_suid_privilege_function_action:testaction:1 - - - - Set Default ip6tables Policy for Incoming Packets - - ocil:ssg-set_ip6tables_default_rule_action:testaction:1 - - - - Account Lockouts Must Be Logged - - ocil:ssg-account_passwords_pam_faillock_audit_action:testaction:1 - - - - Record Any Attempts to Run setsebool - - ocil:ssg-audit_rules_execution_setsebool_action:testaction:1 - - - - Verify that Shared Library Files Have Restrictive Permissions - - ocil:ssg-file_permissions_library_dirs_action:testaction:1 - - - - Restrict Virtual Console Root Logins - - ocil:ssg-securetty_root_login_console_only_action:testaction:1 - - - - Enable Randomized Layout of Virtual Address Space - - ocil:ssg-sysctl_kernel_randomize_va_space_action:testaction:1 - - - - Set Existing Passwords Maximum Age - - ocil:ssg-accounts_password_set_max_life_existing_action:testaction:1 - - - - Add nosuid Option to /tmp - - ocil:ssg-mount_option_tmp_nosuid_action:testaction:1 - - - - Disable X11 Forwarding - - ocil:ssg-sshd_disable_x11_forwarding_action:testaction:1 - - - - Enable Use of Privilege Separation - - ocil:ssg-sshd_use_priv_separation_action:testaction:1 - - - - Ensure that /etc/at.deny does not exist - - ocil:ssg-file_at_deny_not_exist_action:testaction:1 - - - - Install sudo Package - - ocil:ssg-package_sudo_installed_action:testaction:1 - - - - Restrict usage of ptrace to descendant processes - - ocil:ssg-sysctl_kernel_yama_ptrace_scope_action:testaction:1 - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_rp_filter_action:testaction:1 - - - - Set SSH MaxSessions limit - - ocil:ssg-sshd_set_max_sessions_action:testaction:1 - - - - Verify Group Who Owns Crontab - - ocil:ssg-file_groupowner_crontab_action:testaction:1 - - - - Verify Group Who Owns /etc/shells File - - ocil:ssg-file_groupowner_etc_shells_action:testaction:1 - - - - Verify Owner on cron.weekly - - ocil:ssg-file_owner_cron_weekly_action:testaction:1 - - - - Randomize layout of sensitive kernel structures - - ocil:ssg-kernel_config_gcc_plugin_randstruct_action:testaction:1 - - - - Remove the OpenSSH Server Package - - ocil:ssg-package_openssh-server_removed_action:testaction:1 - - - - Disable IEEE 1394 (FireWire) Support - - ocil:ssg-kernel_module_firewire-core_disabled_action:testaction:1 - - - - Disable rlogin Service - - ocil:ssg-service_rlogin_disabled_action:testaction:1 - - - - Disable support for /proc/kkcore - - ocil:ssg-kernel_config_proc_kcore_action:testaction:1 - - - - Verify Group Who Owns passwd File - - ocil:ssg-file_groupowner_etc_passwd_action:testaction:1 - - - - Configure auditing of successful file modifications - - ocil:ssg-audit_modify_success_action:testaction:1 - - - - Enable Dracut FIPS Module - - ocil:ssg-enable_dracut_fips_module_action:testaction:1 - - - - Verify User Who Owns /etc/sudoers File - - ocil:ssg-file_owner_etc_sudoers_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly in /etc/profile - - ocil:ssg-accounts_umask_etc_profile_action:testaction:1 - - - - Enable Encrypted X11 Forwarding - - ocil:ssg-sshd_enable_x11_forwarding_action:testaction:1 - - - - Prevent Unrestricted Mail Relaying - - ocil:ssg-postfix_prevent_unrestricted_relay_action:testaction:1 - - - - Ensure the audit Subsystem is Installed - - ocil:ssg-package_audit_installed_action:testaction:1 - - - - Set Password Hashing Rounds in /etc/login.defs - - ocil:ssg-set_password_hashing_min_rounds_logindefs_action:testaction:1 - - - - Configure Firewalld to Trust Loopback Traffic - - ocil:ssg-firewalld_loopback_traffic_trusted_action:testaction:1 - - - - Verify Owner on cron.monthly - - ocil:ssg-file_owner_cron_monthly_action:testaction:1 - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_router_solicitations_action:testaction:1 - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_log_martians_action:testaction:1 - - - - Do not allow usercopy whitelist violations to fallback to object size - - ocil:ssg-kernel_config_hardened_usercopy_fallback_action:testaction:1 - - - - Record Any Attempts to Run semanage - - ocil:ssg-audit_rules_execution_semanage_action:testaction:1 - - - - Ensure Sudo Logfile Exists - sudo logfile - - ocil:ssg-sudo_custom_logfile_action:testaction:1 - - - - Disable Core Dumps for All Users - - ocil:ssg-disable_users_coredumps_action:testaction:1 - - - - Configure file name of core dumps - - ocil:ssg-sysctl_kernel_core_uses_pid_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/passwd - - ocil:ssg-audit_rules_usergroup_modification_passwd_action:testaction:1 - - - - Generate some entropy during boot and runtime - - ocil:ssg-kernel_config_gcc_plugin_latent_entropy_action:testaction:1 - - - - Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config - - ocil:ssg-harden_sshd_macs_openssh_conf_crypto_policy_action:testaction:1 - - - - Enable the kerberos_enabled SELinux Boolean - - ocil:ssg-sebool_kerberos_enabled_action:testaction:1 - - - - Verify Permissions on Backup passwd File - - ocil:ssg-file_permissions_backup_etc_passwd_action:testaction:1 - - - - Disable graphical user interface - - ocil:ssg-xwindows_remove_packages_action:testaction:1 - - - - Record Any Attempts to Run seunshare - - ocil:ssg-audit_rules_execution_seunshare_action:testaction:1 - - - - Ensure invoking users password for privilege escalation when using sudo - - ocil:ssg-sudoers_validate_passwd_action:testaction:1 - - - - Add nodev Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_nodev_action:testaction:1 - - - - Enable checks on linked list manipulation - - ocil:ssg-kernel_config_debug_list_action:testaction:1 - - - - Verify Group Who Owns /etc/chrony.keys File - - ocil:ssg-file_groupowner_etc_chrony_keys_action:testaction:1 - - - - Kernel panic oops - - ocil:ssg-kernel_config_panic_on_oops_action:testaction:1 - - - - Disable loading and unloading of kernel modules - - ocil:ssg-sysctl_kernel_modules_disabled_action:testaction:1 - - - - Ensure /var/log Located On Separate Partition - - ocil:ssg-partition_for_var_log_action:testaction:1 - - - - Verify Group Who Owns group File - - ocil:ssg-file_groupowner_etc_group_action:testaction:1 - - - - Disable network management of chrony daemon - - ocil:ssg-chronyd_no_chronyc_network_action:testaction:1 - - - - Ensure gnutls-utils is installed - - ocil:ssg-package_gnutls-utils_installed_action:testaction:1 - - - - Disable debug-shell SystemD Service - - ocil:ssg-service_debug-shell_disabled_action:testaction:1 - - - - Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config - - ocil:ssg-harden_sshd_macs_opensshserver_conf_crypto_policy_action:testaction:1 - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_pinfo_action:testaction:1 - - - - Randomize the kernel memory sections - - ocil:ssg-kernel_config_randomize_memory_action:testaction:1 - - - - Disable the IPv6 protocol - - ocil:ssg-kernel_config_ipv6_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - umount - - ocil:ssg-audit_rules_dac_modification_umount_action:testaction:1 - - - - Enable syslog-ng Service - - ocil:ssg-service_syslogng_enabled_action:testaction:1 - - - - Disable the selinuxuser_execheap SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execheap_action:testaction:1 - - - - Configure Libreswan to use System Crypto Policy - - ocil:ssg-configure_libreswan_crypto_policy_action:testaction:1 - - - - Enable the selinuxuser_execmod SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execmod_action:testaction:1 - - - - Verify User Who Owns Backup gshadow File - - ocil:ssg-file_owner_backup_etc_gshadow_action:testaction:1 - - - - Disable Mounting of cramfs - - ocil:ssg-kernel_module_cramfs_disabled_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chsh - - ocil:ssg-audit_rules_privileged_commands_chsh_action:testaction:1 - - - - Verify Group Who Owns /etc/iptables Directory - - ocil:ssg-directory_groupowner_etc_iptables_action:testaction:1 - - - - Install the pcsc-lite package - - ocil:ssg-package_pcsc-lite_installed_action:testaction:1 - - - - Ensure No Device Files are Unlabeled by SELinux - - ocil:ssg-selinux_all_devicefiles_labeled_action:testaction:1 - - - - zero-init everything passed by reference - - ocil:ssg-kernel_config_gcc_plugin_structleak_byref_all_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - - ocil:ssg-audit_rules_kernel_module_loading_finit_action:testaction:1 - - - - Ensure PAM Displays Last Logon/Access Notification - - ocil:ssg-display_login_attempts_action:testaction:1 - - - - Configure Multiple DNS Servers in /etc/resolv.conf - - ocil:ssg-network_configure_name_resolution_action:testaction:1 - - - - Configure Microarchitectural Data Sampling mitigation - - ocil:ssg-grub2_mds_argument_action:testaction:1 - - - - Install AIDE - - ocil:ssg-package_aide_installed_action:testaction:1 - - - - Install rear Package - - ocil:ssg-package_rear_installed_action:testaction:1 - - - - Add noexec Option to /home - - ocil:ssg-mount_option_home_noexec_action:testaction:1 - - - - Verify Group Who Owns /var/log/messages File - - ocil:ssg-file_groupowner_var_log_messages_action:testaction:1 - - - - Set Default firewalld Zone for Incoming Packets - - ocil:ssg-set_firewalld_default_zone_action:testaction:1 - - - - Verify Only Root Has UID 0 - - ocil:ssg-accounts_no_uid_except_zero_action:testaction:1 - - - - Verify that System Executables Have Restrictive Permissions - - ocil:ssg-file_permissions_binary_dirs_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - - ocil:ssg-audit_rules_privileged_commands_userhelper_action:testaction:1 - - - - Ensure syslog-ng is Installed - - ocil:ssg-package_syslogng_installed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - - ocil:ssg-audit_rules_privileged_commands_gpasswd_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - - ocil:ssg-audit_rules_file_deletion_events_action:testaction:1 - - - - Verify /boot/grub2/user.cfg User Ownership - - ocil:ssg-file_owner_user_cfg_action:testaction:1 - - - - Disable the use of user namespaces - - ocil:ssg-sysctl_user_max_user_namespaces_action:testaction:1 - - - - Configure dnf-automatic to Install Available Updates Automatically - - ocil:ssg-dnf-automatic_apply_updates_action:testaction:1 - - - - Configure auditd mail_acct Action on Low Disk Space - - ocil:ssg-auditd_data_retention_action_mail_acct_action:testaction:1 - - - - Ensure McAfee Endpoint Security for Linux (ENSL) is running - - ocil:ssg-agent_mfetpd_running_action:testaction:1 - - - - Disable legacy (BSD) PTY support - - ocil:ssg-kernel_config_legacy_ptys_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - rename - - ocil:ssg-audit_rules_file_deletion_events_rename_action:testaction:1 - - - - Add nosuid Option to Removable Media Partitions - - ocil:ssg-mount_option_nosuid_removable_partitions_action:testaction:1 - - - - Ensure auditd Collects Information on Exporting to Media (successful) - - ocil:ssg-audit_rules_media_export_action:testaction:1 - - - - Verify Owner on cron.hourly - - ocil:ssg-file_owner_cron_hourly_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Permissions - - ocil:ssg-file_permissions_efi_user_cfg_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - passwd - - ocil:ssg-audit_rules_privileged_commands_passwd_action:testaction:1 - - - - Configure Sending and Accepting Shared Media Redirects by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_shared_media_action:testaction:1 - - - - Ensure SELinux State is Enforcing - - ocil:ssg-selinux_state_action:testaction:1 - - - - Limit Password Reuse: system-auth - - ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_action:testaction:1 - - - - Log USBGuard daemon audit events using Linux Audit - - ocil:ssg-configure_usbguard_auditbackend_action:testaction:1 - - - - Verify Permissions on cron.monthly - - ocil:ssg-file_permissions_cron_monthly_action:testaction:1 - - - - Disable the 32-bit vDSO - - ocil:ssg-kernel_config_compat_vdso_action:testaction:1 - - - - Configure Firewalld to Use the Nftables Backend - - ocil:ssg-firewalld-backend_action:testaction:1 - - - - Verify Group Ownership of System Login Banner for Remote Connections - - ocil:ssg-file_groupowner_etc_issue_net_action:testaction:1 - - - - Ensure tmp.mount Unit Is Enabled - - ocil:ssg-systemd_tmp_mount_enabled_action:testaction:1 - - - - Add nosuid Option to /boot/efi - - ocil:ssg-mount_option_boot_efi_nosuid_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - setxattr - - ocil:ssg-audit_rules_dac_modification_setxattr_action:testaction:1 - - - - Verify Group Who Owns /etc/selinux Directory - - ocil:ssg-directory_groupowner_etc_selinux_action:testaction:1 - - - - Configure SELinux Policy - - ocil:ssg-selinux_policytype_action:testaction:1 - - - - Disable vsyscall mapping - - ocil:ssg-kernel_config_legacy_vsyscall_none_action:testaction:1 - - - - Verify nftables Service is Disabled - - ocil:ssg-service_nftables_disabled_action:testaction:1 - - - - Verify User Who Owns passwd File - - ocil:ssg-file_owner_etc_passwd_action:testaction:1 - - - - Configure immutable Audit login UIDs - - ocil:ssg-audit_immutable_login_uids_action:testaction:1 - - - - All GIDs referenced in /etc/passwd must be defined in /etc/group - - ocil:ssg-gid_passwd_group_same_action:testaction:1 - - - - Ensure Logrotate Runs Periodically - - ocil:ssg-ensure_logrotate_activated_action:testaction:1 - - - - Uninstall setroubleshoot-server Package - - ocil:ssg-package_setroubleshoot-server_removed_action:testaction:1 - - - - Add nodev Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_nodev_action:testaction:1 - - - - Set Account Expiration Following Inactivity - - ocil:ssg-account_disable_post_pw_expiration_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - - ocil:ssg-audit_rules_privileged_commands_ssh_keysign_action:testaction:1 - - - - Audit Tools Must Have a Mode of 0755 or Less Permissive - - ocil:ssg-file_audit_tools_permissions_action:testaction:1 - - - - Verify Group Who Owns /etc/ipsec.conf File - - ocil:ssg-file_groupowner_etc_ipsec_conf_action:testaction:1 - - - - Record Attempts to perform maintenance activities - - ocil:ssg-audit_sudo_log_events_action:testaction:1 - - - - Disable mutable hooks - - ocil:ssg-kernel_config_security_writable_hooks_action:testaction:1 - - - - Enforce usage of pam_wheel for su authentication - - ocil:ssg-use_pam_wheel_for_su_action:testaction:1 - - - - Disable KDump Kernel Crash Analyzer (kdump) - - ocil:ssg-service_kdump_disabled_action:testaction:1 - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_action:testaction:1 - - - - Disable GNOME3 Automount running - - ocil:ssg-dconf_gnome_disable_autorun_action:testaction:1 - - - - Ensure Logs Sent To Remote Host - - ocil:ssg-rsyslog_remote_loghost_action:testaction:1 - - - - Ensure All SUID Executables Are Authorized - - ocil:ssg-file_permissions_unauthorized_suid_action:testaction:1 - - - - Verify User Who Owns /var/log/syslog File - - ocil:ssg-file_owner_var_log_syslog_action:testaction:1 - - - - Verify Group Who Owns gshadow File - - ocil:ssg-file_groupowner_etc_gshadow_action:testaction:1 - - - - Prevent Login to Accounts With Empty Password - - ocil:ssg-no_empty_passwords_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - reboot - - ocil:ssg-audit_privileged_commands_reboot_action:testaction:1 - - - - Verify Group Who Owns /var/log/syslog File - - ocil:ssg-file_groupowner_var_log_syslog_action:testaction:1 - - - - Ensure All User Initialization Files Have Mode 0740 Or Less Permissive - - ocil:ssg-file_permission_user_init_files_action:testaction:1 - - - - Record Attempts to Alter Time Through clock_settime - - ocil:ssg-audit_rules_time_clock_settime_action:testaction:1 - - - - Disable merging of slabs with similar size - - ocil:ssg-grub2_slab_nomerge_argument_action:testaction:1 - - - - Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config - - ocil:ssg-harden_sshd_ciphers_openssh_conf_crypto_policy_action:testaction:1 - - - - Set Boot Loader Password in grub2 - - ocil:ssg-grub2_password_action:testaction:1 - - - - Verify Permissions on /var/log/syslog File - - ocil:ssg-file_permissions_var_log_syslog_action:testaction:1 - - - - Verify Group Who Owns /etc/cron.allow file - - ocil:ssg-file_groupowner_cron_allow_action:testaction:1 - - - - Configure dnf-automatic to Install Only Security Updates - - ocil:ssg-dnf-automatic_security_updates_only_action:testaction:1 - - - - Harden the operation of the BPF just-in-time compiler - - ocil:ssg-sysctl_net_core_bpf_jit_harden_action:testaction:1 - - - - Set SSH Client Alive Interval - - ocil:ssg-sshd_set_idle_timeout_action:testaction:1 - - - - Verify User Who Owns Backup passwd File - - ocil:ssg-file_owner_backup_etc_passwd_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - removexattr - - ocil:ssg-audit_rules_dac_modification_removexattr_action:testaction:1 - - - - Ensure System Log Files Have Correct Permissions - - ocil:ssg-rsyslog_files_permissions_action:testaction:1 - - - - Ensure the Default C Shell Umask is Set Correctly - - ocil:ssg-accounts_umask_etc_csh_cshrc_action:testaction:1 - - - - Disable kernel support for MISC binaries - - ocil:ssg-kernel_config_binfmt_misc_action:testaction:1 - - - - Configure Polyinstantiation of /tmp Directories - - ocil:ssg-accounts_polyinstantiated_tmp_action:testaction:1 - - - - Verify Group Who Owns /etc/ipsec.secrets File - - ocil:ssg-file_groupowner_etc_ipsec_secrets_action:testaction:1 - - - - Shutdown System When Auditing Failures Occur - - ocil:ssg-audit_rules_system_shutdown_action:testaction:1 - - - - Make the kernel text and rodata read-only - - ocil:ssg-kernel_config_strict_kernel_rwx_action:testaction:1 - - - - Avoid speculative indirect branches in kernel - - ocil:ssg-kernel_config_retpoline_action:testaction:1 - - - - Set PAM''s Password Hashing Algorithm - password-auth - - ocil:ssg-set_password_hashing_algorithm_passwordauth_action:testaction:1 - - - - Verify that Shared Library Files Have Root Ownership - - ocil:ssg-file_ownership_library_dirs_action:testaction:1 - - - - Enable Smartcards in SSSD - - ocil:ssg-sssd_enable_smartcards_action:testaction:1 - - - - Verify ufw Enabled - - ocil:ssg-service_ufw_enabled_action:testaction:1 - - - - System Audit Logs Must Have Mode 0640 or Less Permissive - - ocil:ssg-file_permissions_var_log_audit_action:testaction:1 - - - - Ensure /var/tmp Located On Separate Partition - - ocil:ssg-partition_for_var_tmp_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - - ocil:ssg-audit_rules_privileged_commands_pam_timestamp_check_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - unlinkat - - ocil:ssg-audit_rules_file_deletion_events_unlinkat_action:testaction:1 - - - - Enable SSH Server firewalld Firewall Exception - - ocil:ssg-firewalld_sshd_port_enabled_action:testaction:1 - - - - Ensure No World-Writable Files Exist - - ocil:ssg-file_permissions_unauthorized_world_writable_action:testaction:1 - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_arp_ignore_action:testaction:1 - - - - Resolve information before writing to audit logs - - ocil:ssg-auditd_log_format_action:testaction:1 - - - - Set GNOME3 Screensaver Lock Delay After Activation Period - - ocil:ssg-dconf_gnome_screensaver_lock_delay_action:testaction:1 - - - - Restrict Access to Kernel Message Buffer - - ocil:ssg-sysctl_kernel_dmesg_restrict_action:testaction:1 - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - - ocil:ssg-accounts_password_pam_ucredit_action:testaction:1 - - - - Ensure /var/log/audit Located On Separate Partition - - ocil:ssg-partition_for_var_log_audit_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - - ocil:ssg-sysctl_fs_protected_hardlinks_action:testaction:1 - - - - Ensure gpgcheck Enabled for Local Packages - - ocil:ssg-ensure_gpgcheck_local_packages_action:testaction:1 - - - - Enable the USBGuard Service - - ocil:ssg-service_usbguard_enabled_action:testaction:1 - - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - - ocil:ssg-audit_rules_mac_modification_usr_share_action:testaction:1 - - - - Configure SSSD to Expire Offline Credentials - - ocil:ssg-sssd_offline_cred_expiration_action:testaction:1 - - - - Set number of Password Hashing Rounds - system-auth - - ocil:ssg-accounts_password_pam_unix_rounds_system_auth_action:testaction:1 - - - - Enable checks on credential management - - ocil:ssg-kernel_config_debug_credentials_action:testaction:1 - - - - Verify and Correct Ownership with RPM - - ocil:ssg-rpm_verify_ownership_action:testaction:1 - - - - Disable snmpd Service - - ocil:ssg-service_snmpd_disabled_action:testaction:1 - - - - Verify File Hashes with RPM - - ocil:ssg-rpm_verify_hashes_action:testaction:1 - - - - Verify Group Who Owns SSH Server config file - - ocil:ssg-file_groupowner_sshd_config_action:testaction:1 - - - - Install crypto-policies package - - ocil:ssg-package_crypto-policies_installed_action:testaction:1 - - - - Ensure SMEP is not disabled during boot - - ocil:ssg-grub2_nosmep_argument_absent_action:testaction:1 - - - - Install audispd-plugins Package - - ocil:ssg-package_audispd-plugins_installed_action:testaction:1 - - - - Enable SLUB/SLAB allocator poisoning - - ocil:ssg-grub2_slub_debug_argument_action:testaction:1 - - - - Verify User Who Owns Backup shadow File - - ocil:ssg-file_groupowner_backup_etc_shadow_action:testaction:1 - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdrivermode_action:testaction:1 - - - - User a virtually-mapped stack - - ocil:ssg-kernel_config_vmap_stack_action:testaction:1 - - - - Verify Group Who Owns /var/log Directory - - ocil:ssg-file_groupowner_var_log_action:testaction:1 - - - - Harden SSH client Crypto Policy - - ocil:ssg-harden_ssh_client_crypto_policy_action:testaction:1 - - - - Verify Permissions on Backup gshadow File - - ocil:ssg-file_permissions_backup_etc_gshadow_action:testaction:1 - - - - Ensure All-Squashing Disabled On All Exports - - ocil:ssg-no_all_squash_exports_action:testaction:1 - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - - ocil:ssg-account_password_pam_faillock_system_auth_action:testaction:1 - - - - Disable GSSAPI Authentication - - ocil:ssg-sshd_disable_gssapi_auth_action:testaction:1 - - - - Enable TCP/IP syncookie support - - ocil:ssg-kernel_config_syn_cookies_action:testaction:1 - - - - Verify User Who Owns Backup group File - - ocil:ssg-file_owner_backup_etc_group_action:testaction:1 - - - - Set type of computer node name logging in audit logs - - ocil:ssg-auditd_name_format_action:testaction:1 - - - - Disable telnet Service - - ocil:ssg-service_telnet_disabled_action:testaction:1 - - - - Verify Permissions On /etc/selinux Directory - - ocil:ssg-directory_permissions_etc_selinux_action:testaction:1 - - - - Disallow kernel profiling by unprivileged users - - ocil:ssg-sysctl_kernel_perf_event_paranoid_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lremovexattr - - ocil:ssg-audit_rules_dac_modification_lremovexattr_action:testaction:1 - - - - Enable SSH Warning Banner - - ocil:ssg-sshd_enable_warning_banner_action:testaction:1 - - - - Audit Tools Must Be Owned by Root - - ocil:ssg-file_audit_tools_ownership_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - unlink - - ocil:ssg-audit_rules_file_deletion_events_unlink_action:testaction:1 - - - - Configure Logind to terminate idle sessions after certain time of inactivity - - ocil:ssg-logind_session_timeout_action:testaction:1 - - - - Configure auditd Disk Error Action on Disk Error - - ocil:ssg-auditd_data_disk_error_action_action:testaction:1 - - - - Enable the GNOME3 Screen Locking On Smartcard Removal - - ocil:ssg-dconf_gnome_lock_screen_on_smartcard_removal_action:testaction:1 - - - - Record Events that Modify the System's Mandatory Access Controls - - ocil:ssg-audit_rules_mac_modification_action:testaction:1 - - - - Verify Permissions On /etc/ipsec.secrets File - - ocil:ssg-file_permissions_etc_ipsec_secrets_action:testaction:1 - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_redirects_action:testaction:1 - - - - Disable SSH Root Login - - ocil:ssg-sshd_disable_root_login_action:testaction:1 - - - - Verify Group Ownership on SSH Server Public *.pub Key Files - - ocil:ssg-file_groupownership_sshd_pub_key_action:testaction:1 - - - - Configure auditing of unsuccessful file accesses - - ocil:ssg-audit_access_failed_action:testaction:1 - - - - Add noexec Option to /var - - ocil:ssg-mount_option_var_noexec_action:testaction:1 - - - - Remove telnet Clients - - ocil:ssg-package_telnet_removed_action:testaction:1 - - - - Set SSH Daemon LogLevel to VERBOSE - - ocil:ssg-sshd_set_loglevel_verbose_action:testaction:1 - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_router_solicitations_action:testaction:1 - - - - Make the module text and rodata read-only - - ocil:ssg-kernel_config_strict_module_rwx_action:testaction:1 - - - - Set Root Account Password Maximum Age - - ocil:ssg-accounts_password_set_max_life_root_action:testaction:1 - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_defrtr_action:testaction:1 - - - - Disable SSH TCP Forwarding - - ocil:ssg-sshd_disable_tcp_forwarding_action:testaction:1 - - - - Verify Ownership on SSH Server Private *_key Key Files - - ocil:ssg-file_ownership_sshd_private_key_action:testaction:1 - - - - SSSD Has a Correct Trust Anchor - - ocil:ssg-sssd_has_trust_anchor_action:testaction:1 - - - - Set Password Maximum Consecutive Repeating Characters - - ocil:ssg-accounts_password_pam_maxrepeat_action:testaction:1 - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty - - ocil:ssg-sudo_add_use_pty_action:testaction:1 - - - - Configure the secure_mode_insmod SELinux Boolean - - ocil:ssg-sebool_secure_mode_insmod_action:testaction:1 - - - - Configure auditing of loading and unloading of kernel modules - - ocil:ssg-audit_module_load_action:testaction:1 - - - - Verify Permissions on SSH Server Private *_key Key Files - - ocil:ssg-file_permissions_sshd_private_key_action:testaction:1 - - - - Configure System to Forward All Mail For The Root Account - - ocil:ssg-postfix_client_configure_mail_alias_action:testaction:1 - - - - Verify Group Who Owns cron.d - - ocil:ssg-file_groupowner_cron_d_action:testaction:1 - - - - Use Centralized and Automated Authentication - - ocil:ssg-account_use_centralized_automated_auth_action:testaction:1 - - - - Verify Permissions on /etc/cron.allow file - - ocil:ssg-file_permissions_cron_allow_action:testaction:1 - - - - Don't target root user in the sudoers file - - ocil:ssg-sudoers_no_root_target_action:testaction:1 - - - - Configure auditd Disk Full Action when Disk Space Is Full - - ocil:ssg-auditd_data_disk_full_action_stig_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_source_route_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - mount - - ocil:ssg-audit_rules_privileged_commands_mount_action:testaction:1 - - - - Install policycoreutils Package - - ocil:ssg-package_policycoreutils_installed_action:testaction:1 - - - - Prefer to use a 64-bit Operating System when supported - - ocil:ssg-prefer_64bit_os_action:testaction:1 - - - - Configure Notification of Post-AIDE Scan Details - - ocil:ssg-aide_scan_notification_action:testaction:1 - - - - Modify the System Login Banner for Remote Connections - - ocil:ssg-banner_etc_issue_net_action:testaction:1 - - - - Configure System to Forward All Mail From Postmaster to The Root Account - - ocil:ssg-postfix_client_configure_mail_alias_postmaster_action:testaction:1 - - - - The Chrony package is installed - - ocil:ssg-package_chrony_installed_action:testaction:1 - - - - Configure maximum number of process identifiers - - ocil:ssg-sysctl_kernel_pid_max_action:testaction:1 - - - - Verify Permissions on /var/log Directory - - ocil:ssg-file_permissions_var_log_action:testaction:1 - - - - Poison kernel stack before returning from syscalls - - ocil:ssg-kernel_config_gcc_plugin_stackleak_action:testaction:1 - - - - Enable FIPS Mode - - ocil:ssg-enable_fips_mode_action:testaction:1 - - - - Ensure There Are No Accounts With Blank or Null Passwords - - ocil:ssg-no_empty_passwords_etc_shadow_action:testaction:1 - - - - Ensure All Files Are Owned by a User - - ocil:ssg-no_files_unowned_by_user_action:testaction:1 - - - - Install usbguard Package - - ocil:ssg-package_usbguard_installed_action:testaction:1 - - - - Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC - - ocil:ssg-sudo_add_noexec_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - - ocil:ssg-audit_rules_privileged_commands_postqueue_action:testaction:1 - - - - Install scap-security-guide Package - - ocil:ssg-package_scap-security-guide_installed_action:testaction:1 - - - - Disable storing core dumps - - ocil:ssg-sysctl_kernel_core_pattern_empty_string_action:testaction:1 - - - - Limit CPU consumption of the Perf system - - ocil:ssg-sysctl_kernel_perf_cpu_time_max_percent_action:testaction:1 - - - - Set the Boot Loader Admin Username to a Non-Default Value - - ocil:ssg-grub2_admin_username_action:testaction:1 - - - - Configure auditing of unsuccessful file deletions - - ocil:ssg-audit_delete_failed_action:testaction:1 - - - - Ensure PAM password complexity module is enabled in password-auth - - ocil:ssg-accounts_password_pam_pwquality_password_auth_action:testaction:1 - - - - Explicit arguments in sudo specifications - - ocil:ssg-sudoers_explicit_command_args_action:testaction:1 - - - - Disable Avahi Server Software - - ocil:ssg-service_avahi-daemon_disabled_action:testaction:1 - - - - Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty - - ocil:ssg-ensure_pam_wheel_group_empty_action:testaction:1 - - - - Disable storing core dumps - - ocil:ssg-sysctl_kernel_core_pattern_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/gshadow - - ocil:ssg-audit_rules_usergroup_modification_gshadow_action:testaction:1 - - - - Prevent remote hosts from connecting to the proxy display - - ocil:ssg-sshd_x11_use_localhost_action:testaction:1 - - - - Add noexec Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_noexec_action:testaction:1 - - - - Kernel panic timeout - - ocil:ssg-kernel_config_panic_timeout_action:testaction:1 - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_max_addresses_action:testaction:1 - - - - Verify User Who Owns /etc/chrony.keys File - - ocil:ssg-file_owner_etc_chrony_keys_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fremovexattr - - ocil:ssg-audit_rules_dac_modification_fremovexattr_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/group - - ocil:ssg-audit_rules_usergroup_modification_group_action:testaction:1 - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_ip_forward_action:testaction:1 - - - - Enable the pcscd Service - - ocil:ssg-service_pcscd_enabled_action:testaction:1 - - - - Enable poison of pages after freeing - - ocil:ssg-kernel_config_page_poisoning_action:testaction:1 - - - - Verify Permissions on passwd File - - ocil:ssg-file_permissions_etc_passwd_action:testaction:1 - - - - Set PAM''s Password Hashing Algorithm - - ocil:ssg-set_password_hashing_algorithm_systemauth_action:testaction:1 - - - - Configure Backups of User Data - - ocil:ssg-configure_user_data_backups_action:testaction:1 - - - - Only the VDSM User Can Use sudo NOPASSWD - - ocil:ssg-sudo_vdsm_nopasswd_action:testaction:1 - - - - Ensure rsyslog-gnutls is installed - - ocil:ssg-package_rsyslog-gnutls_installed_action:testaction:1 - - - - Configure auditd to use audispd's syslog plugin - - ocil:ssg-auditd_audispd_syslog_plugin_activated_action:testaction:1 - - - - Verify Permissions on Backup group File - - ocil:ssg-file_permissions_backup_etc_group_action:testaction:1 - - - - Verify User Who Owns System.map Files - - ocil:ssg-file_owner_systemmap_action:testaction:1 - - - - Add noexec Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_noexec_action:testaction:1 - - - - Disable Squid - - ocil:ssg-service_squid_disabled_action:testaction:1 - - - - Verify Permissions on crontab - - ocil:ssg-file_permissions_crontab_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate - - ocil:ssg-sudo_remove_no_authenticate_action:testaction:1 - - - - System Audit Logs Must Be Group Owned By Root - - ocil:ssg-file_group_ownership_var_log_audit_action:testaction:1 - - - - The operating system must restrict privilege elevation to authorized personnel - - ocil:ssg-sudo_restrict_privilege_elevation_to_authorized_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - init - - ocil:ssg-audit_privileged_commands_init_action:testaction:1 - - - - Verify Group Who Owns Backup group File - - ocil:ssg-file_groupowner_backup_etc_group_action:testaction:1 - - - - Configure BIND to use System Crypto Policy - - ocil:ssg-configure_bind_crypto_policy_action:testaction:1 - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_accept_default_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - - ocil:ssg-audit_rules_privileged_commands_newgrp_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Regular files - - ocil:ssg-sysctl_fs_protected_regular_action:testaction:1 - - - - Enable auditd Service - - ocil:ssg-service_auditd_enabled_action:testaction:1 - - - - Ensure rsyncd service is disabled - - ocil:ssg-service_rsyncd_disabled_action:testaction:1 - - - - Verify User Who Owns /etc/ipsec.d Directory - - ocil:ssg-directory_owner_etc_ipsecd_action:testaction:1 - - - - Disable kexec system call - - ocil:ssg-kernel_config_kexec_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - rmdir - - ocil:ssg-audit_rules_file_deletion_events_rmdir_action:testaction:1 - - - - Record attempts to alter time through adjtimex - - ocil:ssg-audit_rules_time_adjtimex_action:testaction:1 - - - - Disable SSH Support for User Known Hosts - - ocil:ssg-sshd_disable_user_known_hosts_action:testaction:1 - - - - Verify User Who Owns /var/log Directory - - ocil:ssg-file_owner_var_log_action:testaction:1 - - - - Ensure that chronyd is running under chrony user account - - ocil:ssg-chronyd_run_as_chrony_user_action:testaction:1 - - - - Enable PAM - - ocil:ssg-sshd_enable_pam_action:testaction:1 - - - - Disable Postfix Network Listening - - ocil:ssg-postfix_network_listening_disabled_action:testaction:1 - - - - Verify User Who Owns /etc/sestatus.conf File - - ocil:ssg-file_owner_etc_sestatus_conf_action:testaction:1 - - - - Configure auditd Disk Error Action on Disk Error - - ocil:ssg-auditd_data_disk_error_action_stig_action:testaction:1 - - - - Configure Time Service Maxpoll Interval - - ocil:ssg-chronyd_or_ntpd_set_maxpoll_action:testaction:1 - - - - Add noexec Option to /tmp - - ocil:ssg-mount_option_tmp_noexec_action:testaction:1 - - - - Disable the ssh_sysadm_login SELinux Boolean - - ocil:ssg-sebool_ssh_sysadm_login_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - - ocil:ssg-audit_rules_privileged_commands_action:testaction:1 - - - - Verify Group Who Owns System.map Files - - ocil:ssg-file_groupowner_systemmap_action:testaction:1 - - - - Mount Remote Filesystems with noexec - - ocil:ssg-mount_option_noexec_remote_filesystems_action:testaction:1 - - - - Ensure SSH MaxStartups is configured - - ocil:ssg-sshd_set_maxstartups_action:testaction:1 - - - - Chrony Configure Pool and Server - - ocil:ssg-chronyd_configure_pool_and_server_action:testaction:1 - - - - Verify Group Who Owns /etc/nftables Directory - - ocil:ssg-directory_groupowner_etc_nftables_action:testaction:1 - - - - Verify Group Who Owns cron.daily - - ocil:ssg-file_groupowner_cron_daily_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - - ocil:ssg-audit_rules_privileged_commands_unix_update_action:testaction:1 - - - - Configure auditd space_left on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_percentage_action:testaction:1 - - - - Disable Modprobe Loading of USB Storage Driver - - ocil:ssg-kernel_module_usb-storage_disabled_action:testaction:1 - - - - Set number of Password Hashing Rounds - password-auth - - ocil:ssg-accounts_password_pam_unix_rounds_password_auth_action:testaction:1 - - - - Configure auditing of unsuccessful file modifications - - ocil:ssg-audit_modify_failed_action:testaction:1 - - - - Add noexec Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_noexec_action:testaction:1 - - - - Do not allow ACPI methods to be inserted/replaced at run time - - ocil:ssg-kernel_config_acpi_custom_method_action:testaction:1 - - - - Disable SSH root Login with a Password (Insecure) - - ocil:ssg-sshd_disable_root_password_login_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly For Interactive Users - - ocil:ssg-accounts_umask_interactive_users_action:testaction:1 - - - - Add noexec Option to /boot - - ocil:ssg-mount_option_boot_noexec_action:testaction:1 - - - - Install the SSSD Package - - ocil:ssg-package_sssd_installed_action:testaction:1 - - - - Enable dnf-automatic Timer - - ocil:ssg-timer_dnf-automatic_enabled_action:testaction:1 - - - - Verify Permissions On /etc/crypttab File - - ocil:ssg-file_permissions_etc_crypttab_action:testaction:1 - - - - Configure auditing of unsuccessful ownership changes - - ocil:ssg-audit_owner_change_failed_action:testaction:1 - - - - All Interactive Users Home Directories Must Exist - - ocil:ssg-accounts_user_interactive_home_directory_exists_action:testaction:1 - - - - Generate USBGuard Policy - - ocil:ssg-usbguard_generate_policy_action:testaction:1 - - - - Enable module signature verification - - ocil:ssg-kernel_config_module_sig_action:testaction:1 - - - - Disable Compression Or Set Compression to delayed - - ocil:ssg-sshd_disable_compression_action:testaction:1 - - - - Ensure No Daemons are Unconfined by SELinux - - ocil:ssg-selinux_confinement_of_daemons_action:testaction:1 - - - - Ensure All World-Writable Directories Are Owned by root User - - ocil:ssg-dir_perms_world_writable_root_owned_action:testaction:1 - - - - Record Attempts to Alter Time Through stime - - ocil:ssg-audit_rules_time_stime_action:testaction:1 - - - - Record Any Attempts to Run chcon - - ocil:ssg-audit_rules_execution_chcon_action:testaction:1 - - - - Disable acquiring, saving, and processing core dumps - - ocil:ssg-service_systemd-coredump_disabled_action:testaction:1 - - - - Add nosuid Option to /home - - ocil:ssg-mount_option_home_nosuid_action:testaction:1 - - - - Ensure Log Files Are Owned By Appropriate Group - - ocil:ssg-rsyslog_files_groupownership_action:testaction:1 - - - - Verify Permissions On /etc/iptables Directory - - ocil:ssg-directory_permissions_etc_iptables_action:testaction:1 - - - - Configure auditd flush priority - - ocil:ssg-auditd_data_retention_flush_action:testaction:1 - - - - Add nosuid Option to /var - - ocil:ssg-mount_option_var_nosuid_action:testaction:1 - - - - Enable checks on scatter-gather (SG) table operations - - ocil:ssg-kernel_config_debug_sg_action:testaction:1 - - - - Warn on W+X mappings found at boot - - ocil:ssg-kernel_config_debug_wx_action:testaction:1 - - - - Do Not Allow SSH Environment Options - - ocil:ssg-sshd_do_not_permit_user_env_action:testaction:1 - - - - Configure auditing of successful file accesses - - ocil:ssg-audit_access_success_action:testaction:1 - - - - Ensure All Groups on the System Have Unique Group ID - - ocil:ssg-group_unique_id_action:testaction:1 - - - - The s-nail Package Is Installed - - ocil:ssg-package_s-nail_installed_action:testaction:1 - - - - Verify ownership of System Login Banner for Remote Connections - - ocil:ssg-file_owner_etc_issue_net_action:testaction:1 - - - - Ensure Rsyslog Authenticates Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdriverauthmode_action:testaction:1 - - - - Verify User Who Owns /etc/ipsec.secrets File - - ocil:ssg-file_owner_etc_ipsec_secrets_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on FIFOs - - ocil:ssg-sysctl_fs_protected_fifos_action:testaction:1 - - - - Ensure /var Located On Separate Partition - - ocil:ssg-partition_for_var_action:testaction:1 - - - - Verify User Who Owns /etc/ipsec.conf File - - ocil:ssg-file_owner_etc_ipsec_conf_action:testaction:1 - - - - Add nosuid Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_nosuid_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD - - ocil:ssg-sudo_remove_nopasswd_action:testaction:1 - - - - Add nodev Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_nodev_action:testaction:1 - - - - Set Password Hashing Algorithm in /etc/login.defs - - ocil:ssg-set_password_hashing_algorithm_logindefs_action:testaction:1 - - - - Disable the Automounter - - ocil:ssg-service_autofs_disabled_action:testaction:1 - - - - Verify permissions on System Login Banner for Remote Connections - - ocil:ssg-file_permissions_etc_issue_net_action:testaction:1 - - - - Disable Graphical Environment Startup By Setting Default Target - - ocil:ssg-xwindows_runlevel_target_action:testaction:1 - - - - Disable Ctrl-Alt-Del Burst Action - - ocil:ssg-disable_ctrlaltdel_burstaction_action:testaction:1 - - - - Remove the X Windows Package Group - - ocil:ssg-package_xorg-x11-server-common_removed_action:testaction:1 - - - - Add noexec Option to /var/log - - ocil:ssg-mount_option_var_log_noexec_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - chmod - - ocil:ssg-audit_rules_dac_modification_chmod_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lsetxattr - - ocil:ssg-audit_rules_dac_modification_lsetxattr_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - openat - - ocil:ssg-audit_rules_unsuccessful_file_modification_openat_action:testaction:1 - - - - Verify Permissions On /etc/sudoers File - - ocil:ssg-file_permissions_etc_sudoers_action:testaction:1 - - - - Verify the UEFI Boot Loader grub.cfg Group Ownership - - ocil:ssg-file_groupowner_efi_grub2_cfg_action:testaction:1 - - - - Ensure Software Patches Installed - - ocil:ssg-security_patches_up_to_date_action:testaction:1 - - - - Perform general configuration of Audit for OSPP - - ocil:ssg-audit_ospp_general_action:testaction:1 - - - - Enable cron Service - - ocil:ssg-service_crond_enabled_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_secure_redirects_action:testaction:1 - - - - Verify Permissions on cron.d - - ocil:ssg-file_permissions_cron_d_action:testaction:1 - - - - Ensure rsyslog is Installed - - ocil:ssg-package_rsyslog_installed_action:testaction:1 - - - - Add nodev Option to /var - - ocil:ssg-mount_option_var_nodev_action:testaction:1 - - - - Record attempts to alter time through settimeofday - - ocil:ssg-audit_rules_time_settimeofday_action:testaction:1 - - - - Specify the hash to use when signing modules - - ocil:ssg-kernel_config_module_sig_hash_action:testaction:1 - - - - Disable Accepting Packets Routed Between Local Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_local_action:testaction:1 - - - - Require Authentication for Single User Mode - - ocil:ssg-require_singleuser_auth_action:testaction:1 - - - - Enable GNOME3 Login Warning Banner - - ocil:ssg-dconf_gnome_banner_enabled_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - - ocil:ssg-accounts_password_pam_maxclassrepeat_action:testaction:1 - - - - Set the UEFI Boot Loader Password - - ocil:ssg-grub2_uefi_password_action:testaction:1 - - - - Configure TLS for rsyslog remote logging - - ocil:ssg-rsyslog_remote_tls_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_accept_source_route_action:testaction:1 - - - - Verify Permissions on cron.weekly - - ocil:ssg-file_permissions_cron_weekly_action:testaction:1 - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_defaultnetstreamdriver_action:testaction:1 - - - - Enable the File Access Policy Service - - ocil:ssg-service_fapolicyd_enabled_action:testaction:1 - - - - Uninstall rsh-server Package - - ocil:ssg-package_rsh-server_removed_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fsetxattr - - ocil:ssg-audit_rules_dac_modification_fsetxattr_action:testaction:1 - - - - Disable compatibility with brk() - - ocil:ssg-kernel_config_compat_brk_action:testaction:1 - - - - Randomize slab freelist - - ocil:ssg-kernel_config_slab_freelist_random_action:testaction:1 - - - - Uninstall Sendmail Package - - ocil:ssg-package_sendmail_removed_action:testaction:1 - - - - Configure auditd Disk Full Action when Disk Space Is Full - - ocil:ssg-auditd_data_disk_full_action_action:testaction:1 - - - - Require Re-Authentication When Using the sudo Command - - ocil:ssg-sudo_require_reauthentication_action:testaction:1 - - - - Require Encryption for Remote Access in GNOME3 - - ocil:ssg-dconf_gnome_remote_access_encryption_action:testaction:1 - - - - Verify Group Who Owns /etc/at.allow file - - ocil:ssg-file_groupowner_at_allow_action:testaction:1 - - - - Disable SSH Access via Empty Passwords - - ocil:ssg-sshd_disable_empty_passwords_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo - - ocil:ssg-sudo_require_authentication_action:testaction:1 - - - - Verify Permissions on gshadow File - - ocil:ssg-file_permissions_etc_gshadow_action:testaction:1 - - - - Enable Certmap in SSSD - - ocil:ssg-sssd_enable_certmap_action:testaction:1 - - - - Disable hibernation - - ocil:ssg-kernel_config_hibernation_action:testaction:1 - - - - Disable the GNOME3 Login Restart and Shutdown Buttons - - ocil:ssg-dconf_gnome_disable_restart_shutdown_action:testaction:1 - - - - Configure L1 Terminal Fault mitigations - - ocil:ssg-grub2_l1tf_argument_action:testaction:1 - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_send_redirects_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - crontab - - ocil:ssg-audit_rules_privileged_commands_crontab_action:testaction:1 - - - - Limit Users' SSH Access - - ocil:ssg-sshd_limit_user_access_action:testaction:1 - - - - Ensure All SGID Executables Are Authorized - - ocil:ssg-file_permissions_unauthorized_sgid_action:testaction:1 - - - - Enable randomization of the page allocator - - ocil:ssg-grub2_page_alloc_shuffle_argument_action:testaction:1 - - - - Configure GNOME3 DConf User Profile - - ocil:ssg-enable_dconf_user_profile_action:testaction:1 - - - - Enable GNOME3 Screensaver Idle Activation - - ocil:ssg-dconf_gnome_screensaver_idle_activation_enabled_action:testaction:1 - - - - Enable authselect - - ocil:ssg-enable_authselect_action:testaction:1 - - - - Disable x86 vsyscall emulation - - ocil:ssg-kernel_config_x86_vsyscall_emulation_action:testaction:1 - - - - Ensure System is Not Acting as a Network Sniffer - - ocil:ssg-network_sniffer_disabled_action:testaction:1 - - - - Ensure that /etc/cron.deny does not exist - - ocil:ssg-file_cron_deny_not_exist_action:testaction:1 - - - - Install nftables Package - - ocil:ssg-package_nftables_installed_action:testaction:1 - - - - Verify Group Who Owns cron.hourly - - ocil:ssg-file_groupowner_cron_hourly_action:testaction:1 - - - - Disable Odd Job Daemon (oddjobd) - - ocil:ssg-service_oddjobd_disabled_action:testaction:1 - - - - Ensure all users last password change date is in the past - - ocil:ssg-accounts_password_last_change_is_in_past_action:testaction:1 - - - - Uninstall tftp-server Package - - ocil:ssg-package_tftp-server_removed_action:testaction:1 - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - ocil:ssg-auditd_data_retention_max_log_file_action_stig_action:testaction:1 - - - - Verify that Shared Library Directories Have Root Group Ownership - - ocil:ssg-dir_group_ownership_library_dirs_action:testaction:1 - - - - Configure AIDE to Verify the Audit Tools - - ocil:ssg-aide_check_audit_tools_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - - ocil:ssg-audit_rules_kernel_module_loading_action:testaction:1 - - - - Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems - - ocil:ssg-configured_firewalld_default_deny_action:testaction:1 - - - - Audit Tools Must Be Group-owned by Root - - ocil:ssg-file_audit_tools_group_ownership_action:testaction:1 - - - - Verify Permissions on /etc/shells File - - ocil:ssg-file_permissions_etc_shells_action:testaction:1 - - - - Verify Permissions on SSH Server Public *.pub Key Files - - ocil:ssg-file_permissions_sshd_pub_key_action:testaction:1 - - - - Ensure SSH LoginGraceTime is configured - - ocil:ssg-sshd_set_login_grace_time_action:testaction:1 - - - - Ensure Log Files Are Owned By Appropriate User - - ocil:ssg-rsyslog_files_ownership_action:testaction:1 - - - - Enable Postfix Service - - ocil:ssg-service_postfix_enabled_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - faillock - - ocil:ssg-audit_rules_login_events_faillock_action:testaction:1 - - - - The Installed Operating System Is Vendor Supported - - ocil:ssg-installed_OS_is_vendor_supported_action:testaction:1 - - - - Ensure that User Home Directories are not Group-Writable or World-Readable - - ocil:ssg-file_permissions_home_dirs_action:testaction:1 - - - - Verify Permissions On /etc/sysctl.d Directory - - ocil:ssg-directory_permissions_etc_sysctld_action:testaction:1 - - - - Verify Owner on SSH Server config file - - ocil:ssg-file_owner_sshd_config_action:testaction:1 - - - - Verify the UEFI Boot Loader grub.cfg Permissions - - ocil:ssg-file_permissions_efi_grub2_cfg_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - - ocil:ssg-audit_privileged_commands_shutdown_action:testaction:1 - - - - Verify firewalld Enabled - - ocil:ssg-service_firewalld_enabled_action:testaction:1 - - - - Record Any Attempts to Run chacl - - ocil:ssg-audit_rules_execution_chacl_action:testaction:1 - - - - Uninstall quagga Package - - ocil:ssg-package_quagga_removed_action:testaction:1 - - - - Disable chrony daemon from acting as server - - ocil:ssg-chronyd_client_only_action:testaction:1 - - - - Record Any Attempts to Run ssh-agent - - ocil:ssg-audit_rules_privileged_commands_ssh_agent_action:testaction:1 - - - - Certificate status checking in SSSD - - ocil:ssg-sssd_certificate_verification_action:testaction:1 - - - - Verify Group Who Owns /etc/sestatus.conf File - - ocil:ssg-file_groupowner_etc_sestatus_conf_action:testaction:1 - - - - Uninstall talk Package - - ocil:ssg-package_talk_removed_action:testaction:1 - - - - Harden common str/mem functions against buffer overflows - - ocil:ssg-kernel_config_fortify_source_action:testaction:1 - - - - Disallow merge of slab caches - - ocil:ssg-kernel_config_slab_merge_default_action:testaction:1 - - - - Force frequent session key renegotiation - - ocil:ssg-sshd_rekey_limit_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - open_by_handle_at - - ocil:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at_action:testaction:1 - - - - Verify Permissions on cron.hourly - - ocil:ssg-file_permissions_cron_hourly_action:testaction:1 - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - - ocil:ssg-account_password_pam_faillock_password_auth_action:testaction:1 - - - - Set number of records to cause an explicit flush to audit logs - - ocil:ssg-auditd_freq_action:testaction:1 - - - - Enable automatic signing of all modules - - ocil:ssg-kernel_config_module_sig_all_action:testaction:1 - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_pinfo_action:testaction:1 - - - - Install OpenSSH client software - - ocil:ssg-package_openssh-clients_installed_action:testaction:1 - - - - Unmap kernel when running in userspace (aka KAISER) - - ocil:ssg-kernel_config_unmap_kernel_at_el0_action:testaction:1 - - - - Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server - - ocil:ssg-sssd_ldap_configure_tls_reqcert_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - - ocil:ssg-accounts_password_pam_dictcheck_action:testaction:1 - - - - Verify /boot/grub2/user.cfg User Ownership - - ocil:ssg-file_owner_efi_user_cfg_action:testaction:1 - - - - Detect stack corruption on calls to schedule() - - ocil:ssg-kernel_config_sched_stack_end_check_action:testaction:1 - - - - Ensure logrotate is Installed - - ocil:ssg-package_logrotate_installed_action:testaction:1 - - - - Enable poison without sanity check - - ocil:ssg-kernel_config_page_poisoning_no_sanity_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Session Idle Settings - - ocil:ssg-dconf_gnome_session_idle_user_locks_action:testaction:1 - - - - Verify Permissions on Backup shadow File - - ocil:ssg-file_permissions_backup_etc_shadow_action:testaction:1 - - - - Configure Firewalld to Restrict Loopback Traffic - - ocil:ssg-firewalld_loopback_traffic_restricted_action:testaction:1 - - - - Configure the polyinstantiation_enabled SELinux Boolean - - ocil:ssg-sebool_polyinstantiation_enabled_action:testaction:1 - - - - Specify module signing key to use - - ocil:ssg-kernel_config_module_sig_key_action:testaction:1 - - - - Build and Test AIDE Database - - ocil:ssg-aide_build_database_action:testaction:1 - - - - Verify Group Who Owns /etc/sudoers.d Directory - - ocil:ssg-directory_groupowner_etc_sudoersd_action:testaction:1 - - - - Uninstall vsftpd Package - - ocil:ssg-package_vsftpd_removed_action:testaction:1 + ocil:ssg-account_disable_inactivity_password_auth_action:testaction:1 @@ -244228,1600 +264513,22 @@ fi ocil:ssg-account_disable_inactivity_system_auth_action:testaction:1 - - Set Account Expiration Following Inactivity in password-auth + + Set Account Expiration Following Inactivity - ocil:ssg-account_disable_inactivity_password_auth_action:testaction:1 + ocil:ssg-account_disable_post_pw_expiration_action:testaction:1 - - Set kernel parameter 'crypto.fips_enabled' to 1 + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - ocil:ssg-sysctl_crypto_fips_enabled_action:testaction:1 + ocil:ssg-account_password_pam_faillock_password_auth_action:testaction:1 - - Verify Owner on crontab + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - ocil:ssg-file_owner_crontab_action:testaction:1 - - - - Verify that System Executable Directories Have Restrictive Permissions - - ocil:ssg-dir_permissions_binary_dirs_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Length - - ocil:ssg-accounts_password_pam_minlen_action:testaction:1 - - - - Verify Group Who Owns /etc/ipsec.d Directory - - ocil:ssg-directory_groupowner_etc_ipsecd_action:testaction:1 - - - - Verify User Who Owns /etc/cron.allow file - - ocil:ssg-file_owner_cron_allow_action:testaction:1 - - - - Configure the root Account for Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_deny_root_action:testaction:1 - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_defrtr_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - creat - - ocil:ssg-audit_rules_unsuccessful_file_modification_creat_action:testaction:1 - - - - Harden memory copies between kernel and userspace - - ocil:ssg-kernel_config_hardened_usercopy_action:testaction:1 - - - - Disable GNOME3 Automount Opening - - ocil:ssg-dconf_gnome_disable_automount_open_action:testaction:1 - - - - Disable PubkeyAuthentication Authentication - - ocil:ssg-sshd_disable_pubkey_auth_action:testaction:1 - - - - Configure auditd admin_space_left Action on Low Disk Space - - ocil:ssg-auditd_data_retention_admin_space_left_action_action:testaction:1 - - - - Enforce Usage of pam_wheel with Group Parameter for su Authentication - - ocil:ssg-use_pam_wheel_group_for_su_action:testaction:1 - - - - Account Lockouts Must Persist - - ocil:ssg-account_passwords_pam_faillock_dir_action:testaction:1 - - - - Lock Accounts Must Persist - - ocil:ssg-accounts_passwords_pam_faillock_dir_action:testaction:1 - - - - Configure kernel to zero out memory before allocation - - ocil:ssg-grub2_init_on_alloc_argument_action:testaction:1 - - - - Use Only Strong MACs - - ocil:ssg-sshd_use_strong_macs_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - umount - - ocil:ssg-audit_rules_privileged_commands_umount_action:testaction:1 - - - - Extend Audit Backlog Limit for the Audit Daemon - - ocil:ssg-grub2_audit_backlog_limit_argument_action:testaction:1 - - - - The Postfix package is installed - - ocil:ssg-package_postfix_installed_action:testaction:1 - - - - Trigger a kernel BUG when data corruption is detected - - ocil:ssg-kernel_config_bug_on_data_corruption_action:testaction:1 - - - - Verify Group Who Owns cron.deny - - ocil:ssg-file_groupowner_cron_deny_action:testaction:1 - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_action:testaction:1 - - - - Disallow magic SysRq key - - ocil:ssg-sysctl_kernel_sysrq_action:testaction:1 - - - - Enable systemd-journald Service - - ocil:ssg-service_systemd-journald_enabled_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Special Characters - - ocil:ssg-accounts_password_pam_ocredit_action:testaction:1 - - - - Ensure that Users Path Contains Only Local Directories - - ocil:ssg-accounts_user_home_paths_only_action:testaction:1 - - - - System Audit Logs Must Have Mode 0750 or Less Permissive - - ocil:ssg-directory_permissions_var_log_audit_action:testaction:1 - - - - Configure Low Address Space To Protect From User Allocation - - ocil:ssg-kernel_config_default_mmap_min_addr_action:testaction:1 - - - - Disable GNOME3 Automounting - - ocil:ssg-dconf_gnome_disable_automount_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - open - - ocil:ssg-audit_rules_unsuccessful_file_modification_open_action:testaction:1 - - - - Disable Host-Based Authentication - - ocil:ssg-disable_host_auth_action:testaction:1 - - - - System Audit Logs Must Be Owned By Root - - ocil:ssg-file_ownership_var_log_audit_action:testaction:1 - - - - Add nosuid Option to /boot - - ocil:ssg-mount_option_boot_nosuid_action:testaction:1 - - - - Write Audit Logs to the Disk - - ocil:ssg-auditd_write_logs_action:testaction:1 - - - - Configure auditd space_left Action on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_action_action:testaction:1 - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_max_addresses_action:testaction:1 - - - - Configure ARP filtering for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_arp_filter_action:testaction:1 - - - - Require modules to be validly signed - - ocil:ssg-kernel_config_module_sig_force_action:testaction:1 - - - - Verify that System Executables Have Root Ownership - - ocil:ssg-file_ownership_binary_dirs_action:testaction:1 - - - - Limit Password Reuse - - ocil:ssg-accounts_password_pam_unix_remember_action:testaction:1 - - - - Disable vsyscall emulation - - ocil:ssg-kernel_config_legacy_vsyscall_emulate_action:testaction:1 - - - - Configure auditing of unsuccessful file creations - - ocil:ssg-audit_create_failed_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Group Ownership - - ocil:ssg-file_groupowner_efi_user_cfg_action:testaction:1 - - - - Ensure Oracle Linux GPG Key Installed - - ocil:ssg-ensure_oracle_gpgkey_installed_action:testaction:1 - - - - Include Local Events in Audit Logs - - ocil:ssg-auditd_local_events_action:testaction:1 - - - - Stack Protector buffer overlow detection - - ocil:ssg-kernel_config_stackprotector_action:testaction:1 - - - - Add grpquota Option to /home - - ocil:ssg-mount_option_home_grpquota_action:testaction:1 - - - - Limit Password Reuse: password-auth - - ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_action:testaction:1 - - - - Install the OpenSSH Server Package - - ocil:ssg-package_openssh-server_installed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - - ocil:ssg-audit_rules_privileged_commands_postdrop_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - - ocil:ssg-audit_rules_sudoers_d_action:testaction:1 - - - - Disable Kernel Parameter for IPv6 Forwarding - - ocil:ssg-sysctl_net_ipv6_conf_all_forwarding_action:testaction:1 - - - - Record Attempts to Alter the localtime File - - ocil:ssg-audit_rules_time_watch_localtime_action:testaction:1 - - - - Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_forwarding_action:testaction:1 - - - - Install fapolicyd Package - - ocil:ssg-package_fapolicyd_installed_action:testaction:1 - - - - Set the GNOME3 Login Warning Banner Text - - ocil:ssg-dconf_gnome_login_banner_text_action:testaction:1 - - - - Enforce Spectre v2 mitigation - - ocil:ssg-grub2_spectre_v2_argument_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_source_route_action:testaction:1 - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_autoconf_action:testaction:1 - - - - Prevent applications from mapping low portion of virtual memory - - ocil:ssg-sysctl_vm_mmap_min_addr_action:testaction:1 - - - - Verify Permissions On /etc/ipsec.conf File - - ocil:ssg-file_permissions_etc_ipsec_conf_action:testaction:1 - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - - ocil:ssg-sysctl_net_ipv4_tcp_syncookies_action:testaction:1 - - - - Force initialization of variables containing userspace addresses - - ocil:ssg-kernel_config_gcc_plugin_structleak_action:testaction:1 - - - - Emulate Privileged Access Never (PAN) - - ocil:ssg-kernel_config_arm64_sw_ttbr0_pan_action:testaction:1 - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_disable_ipv6_action:testaction:1 - - - - Add nosuid Option to /srv - - ocil:ssg-mount_option_srv_nosuid_action:testaction:1 - - - - Disable the GNOME3 Login User List - - ocil:ssg-dconf_gnome_disable_user_list_action:testaction:1 - - - - Disable IA32 emulation - - ocil:ssg-kernel_config_ia32_emulation_action:testaction:1 - - - - Disable Recovery Booting - - ocil:ssg-grub2_disable_recovery_action:testaction:1 - - - - Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - ocil:ssg-rsyslog_nolisten_action:testaction:1 - - - - Ensure All Accounts on the System Have Unique Names - - ocil:ssg-account_unique_name_action:testaction:1 - - - - Verify Group Who Owns cron.weekly - - ocil:ssg-file_groupowner_cron_weekly_action:testaction:1 - - - - Install Smart Card Packages For Multifactor Authentication - - ocil:ssg-install_smartcard_packages_action:testaction:1 - - - - Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config - - ocil:ssg-harden_sshd_ciphers_opensshserver_conf_crypto_policy_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg Group Ownership - - ocil:ssg-file_groupowner_grub2_cfg_action:testaction:1 - - - - Enable Kernel Page-Table Isolation (KPTI) - - ocil:ssg-grub2_pti_argument_action:testaction:1 - - - - Verify No netrc Files Exist - - ocil:ssg-no_netrc_files_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - tallylog - - ocil:ssg-audit_rules_login_events_tallylog_action:testaction:1 - - - - System Audit Directories Must Be Group Owned By Root - - ocil:ssg-directory_group_ownership_var_log_audit_action:testaction:1 - - - - All Interactive User Home Directories Must Have mode 0750 Or Less Permissive - - ocil:ssg-file_permissions_home_directories_action:testaction:1 - - - - Ensure nss-tools is installed - - ocil:ssg-package_nss-tools_installed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - at - - ocil:ssg-audit_rules_privileged_commands_at_action:testaction:1 - - - - Verify Group Ownership on SSH Server Private *_key Key Files - - ocil:ssg-file_groupownership_sshd_private_key_action:testaction:1 - - - - Disable SSH Server If Possible - - ocil:ssg-service_sshd_disabled_action:testaction:1 - - - - Configure Polyinstantiation of /var/tmp Directories - - ocil:ssg-accounts_polyinstantiated_var_tmp_action:testaction:1 - - - - Verify Owner on cron.daily - - ocil:ssg-file_owner_cron_daily_action:testaction:1 - - - - Enable logrotate Timer - - ocil:ssg-timer_logrotate_enabled_action:testaction:1 - - - - All Interactive User Home Directories Must Be Group-Owned By The Primary Group - - ocil:ssg-file_groupownership_home_directories_action:testaction:1 - - - - Set Default iptables Policy for Incoming Packets - - ocil:ssg-set_iptables_default_rule_action:testaction:1 - - - - Remove Rsh Trust Files - - ocil:ssg-no_rsh_trust_files_action:testaction:1 - - - - Verify that All World-Writable Directories Have Sticky Bits Set - - ocil:ssg-dir_perms_world_writable_sticky_bits_action:testaction:1 - - - - Configure Auto Configuration on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_autoconf_action:testaction:1 - - - - Remove the kernel mapping in user mode - - ocil:ssg-kernel_config_page_table_isolation_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - kmod - - ocil:ssg-audit_rules_privileged_commands_kmod_action:testaction:1 - - - - Uninstall telnet-server Package - - ocil:ssg-package_telnet-server_removed_action:testaction:1 - - - - Verify User Who Owns /etc/selinux Directory - - ocil:ssg-directory_owner_etc_selinux_action:testaction:1 - - - - Install openscap-scanner Package - - ocil:ssg-package_openscap-scanner_installed_action:testaction:1 - - - - Ensure the Logon Failure Delay is Set Correctly in login.defs - - ocil:ssg-accounts_logon_fail_delay_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - - ocil:ssg-audit_rules_kernel_module_loading_delete_action:testaction:1 - - - - Verify User Who Owns shadow File - - ocil:ssg-file_owner_etc_shadow_action:testaction:1 - - - - Verify User Who Owns /etc/crypttab File - - ocil:ssg-file_owner_etc_crypttab_action:testaction:1 - - - - Verify Permissions On /etc/chrony.keys File - - ocil:ssg-file_permissions_etc_chrony_keys_action:testaction:1 - - - - Verify that Shared Library Directories Have Restrictive Permissions - - ocil:ssg-dir_permissions_library_dirs_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchown - - ocil:ssg-audit_rules_dac_modification_fchown_action:testaction:1 - - - - Disable At Service (atd) - - ocil:ssg-service_atd_disabled_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - - ocil:ssg-audit_rules_sudoers_action:testaction:1 - - - - Strong Stack Protector - - ocil:ssg-kernel_config_stackprotector_strong_action:testaction:1 - - - - Configure the Firewalld Ports - - ocil:ssg-configure_firewalld_ports_action:testaction:1 - - - - Install policycoreutils-python-utils package - - ocil:ssg-package_policycoreutils-python-utils_installed_action:testaction:1 - - - - Configure AIDE to Use FIPS 140-2 for Validating Hashes - - ocil:ssg-aide_use_fips_hashes_action:testaction:1 - - - - Remove Host-Based Authentication Files - - ocil:ssg-no_host_based_files_action:testaction:1 - - - - Ensure SMAP is not disabled during boot - - ocil:ssg-grub2_nosmap_argument_absent_action:testaction:1 - - - - Verify iptables Enabled - - ocil:ssg-service_iptables_enabled_action:testaction:1 - - - - Enable different security models - - ocil:ssg-kernel_config_security_action:testaction:1 - - - - Disable CAN Support - - ocil:ssg-kernel_module_can_disabled_action:testaction:1 - - - - Perform full reference count validation - - ocil:ssg-kernel_config_refcount_full_action:testaction:1 - - - - Enable rsyslog Service - - ocil:ssg-service_rsyslog_enabled_action:testaction:1 - - - - Restrict Serial Port Root Logins - - ocil:ssg-restrict_serial_port_logins_action:testaction:1 - - - - Appropriate Action Must be Setup When the Internal Audit Event Queue is Full - - ocil:ssg-auditd_overflow_action_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - su - - ocil:ssg-audit_rules_privileged_commands_su_action:testaction:1 - - - - Configure SNMP Service to Use Only SNMPv3 or Newer - - ocil:ssg-snmpd_use_newer_protocol_action:testaction:1 - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_redirects_action:testaction:1 - - - - Verify User Who Owns /etc/sudoers.d Directory - - ocil:ssg-directory_owner_etc_sudoersd_action:testaction:1 - - - - Ensure that System Accounts Are Locked - - ocil:ssg-no_password_auth_for_systemaccounts_action:testaction:1 - - - - Enable SSH Print Last Log - - ocil:ssg-sshd_print_last_log_action:testaction:1 - - - - Mount Remote Filesystems with nosuid - - ocil:ssg-mount_option_nosuid_remote_filesystems_action:testaction:1 - - - - Verify that System Executable Have Root Ownership - - ocil:ssg-dir_ownership_binary_dirs_action:testaction:1 - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_action:testaction:1 - - - - Configure session renegotiation for SSH client - - ocil:ssg-ssh_client_rekey_limit_action:testaction:1 - - - - Configure SSH to use System Crypto Policy - - ocil:ssg-configure_ssh_crypto_policy_action:testaction:1 - - - - Make the auditd Configuration Immutable - - ocil:ssg-audit_rules_immutable_action:testaction:1 - - - - Configure PAM in SSSD Services - - ocil:ssg-sssd_enable_pam_services_action:testaction:1 - - - - Set Password Minimum Length in login.defs - - ocil:ssg-accounts_password_minlen_login_defs_action:testaction:1 - - - - Verify Permissions on /etc/at.allow file - - ocil:ssg-file_permissions_at_allow_action:testaction:1 - - - - Verify Group Who Owns /etc/crypttab File - - ocil:ssg-file_groupowner_etc_crypttab_action:testaction:1 - - - - Harden slab freelist metadata - - ocil:ssg-kernel_config_slab_freelist_hardened_action:testaction:1 - - - - Kernel panic on oops - - ocil:ssg-sysctl_kernel_panic_on_oops_action:testaction:1 - - - - Set Default iptables Policy for Forwarded Packets - - ocil:ssg-set_iptables_default_rule_forward_action:testaction:1 - - - - Enable support for BUG() - - ocil:ssg-kernel_config_bug_action:testaction:1 - - - - Verify Group Who Owns shadow File - - ocil:ssg-file_groupowner_etc_shadow_action:testaction:1 - - - - Disable XDMCP in GDM - - ocil:ssg-gnome_gdm_disable_xdmcp_action:testaction:1 - - - - Set SSH Client Alive Count Max to zero - - ocil:ssg-sshd_set_keepalive_0_action:testaction:1 - - - - Disable Network Router Discovery Daemon (rdisc) - - ocil:ssg-service_rdisc_disabled_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Enforce for root User - - ocil:ssg-accounts_password_pam_enforce_root_action:testaction:1 - - - - Uninstall tuned Package - - ocil:ssg-package_tuned_removed_action:testaction:1 - - - - Modify the System Message of the Day Banner - - ocil:ssg-banner_etc_motd_action:testaction:1 - - - - Verify Permissions on /etc/audit/auditd.conf - - ocil:ssg-file_permissions_etc_audit_auditd_action:testaction:1 - - - - Enable NX or XD Support in the BIOS - - ocil:ssg-bios_enable_execution_restrictions_action:testaction:1 - - - - Configure Periodic Execution of AIDE - - ocil:ssg-aide_periodic_cron_checking_action:testaction:1 - - - - Ensure All Accounts on the System Have Unique User IDs - - ocil:ssg-account_unique_id_action:testaction:1 - - - - Uninstall bind Package - - ocil:ssg-package_bind_removed_action:testaction:1 - - - - Ensure /dev/shm is configured - - ocil:ssg-partition_for_dev_shm_action:testaction:1 - - - - Disable the LDT (local descriptor table) - - ocil:ssg-kernel_config_modify_ldt_syscall_action:testaction:1 - - - - Record Any Attempts to Run setfiles - - ocil:ssg-audit_rules_execution_setfiles_action:testaction:1 - - - - Enable the auditadm_exec_content SELinux Boolean - - ocil:ssg-sebool_auditadm_exec_content_action:testaction:1 - - - - Install McAfee Endpoint Security for Linux (ENSL) - - ocil:ssg-package_mcafeetp_installed_action:testaction:1 - - - - Verify Any Configured IPSec Tunnel Connections - - ocil:ssg-libreswan_approved_tunnels_action:testaction:1 - - - - Implement Blank Screensaver - - ocil:ssg-dconf_gnome_screensaver_mode_blank_action:testaction:1 - - - - Uninstall gssproxy Package - - ocil:ssg-package_gssproxy_removed_action:testaction:1 - - - - NetworkManager DNS Mode Must Be Must Configured - - ocil:ssg-networkmanager_dns_mode_action:testaction:1 - - - - Add nosuid Option to /opt - - ocil:ssg-mount_option_opt_nosuid_action:testaction:1 - - - - Ensure that Root's Path Does Not Include World or Group-Writable Directories - - ocil:ssg-accounts_root_path_dirs_no_write_action:testaction:1 - - - - Set Lockout Time for Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_unlock_time_action:testaction:1 - - - - Enable Yama support - - ocil:ssg-kernel_config_security_yama_action:testaction:1 - - - - Configure OpenSSL library to use System Crypto Policy - - ocil:ssg-configure_openssl_crypto_policy_action:testaction:1 - - - - System Audit Directories Must Be Owned By Root - - ocil:ssg-directory_ownership_var_log_audit_action:testaction:1 - - - - User Initialization Files Must Be Owned By the Primary User - - ocil:ssg-accounts_user_dot_user_ownership_action:testaction:1 - - - - Configure Kerberos to use System Crypto Policy - - ocil:ssg-configure_kerberos_crypto_policy_action:testaction:1 - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_drop_gratuitous_arp_action:testaction:1 - - - - Configure AIDE to Verify Access Control Lists (ACLs) - - ocil:ssg-aide_verify_acls_action:testaction:1 - - - - Enable Auditing for Processes Which Start Prior to the Audit Daemon - - ocil:ssg-grub2_audit_argument_action:testaction:1 - - - - Modify the System Login Banner - - ocil:ssg-banner_etc_issue_action:testaction:1 - - - - Disable ATM Support - - ocil:ssg-kernel_module_atm_disabled_action:testaction:1 - - - - Configure CA certificate for rsyslog remote logging - - ocil:ssg-rsyslog_remote_tls_cacert_action:testaction:1 - - - - Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) - - ocil:ssg-audit_rules_unsuccessful_file_modification_action:testaction:1 - - - - Configure auditing of unsuccessful permission changes - - ocil:ssg-audit_perm_change_failed_action:testaction:1 - - - - Disable Kernel Image Loading - - ocil:ssg-sysctl_kernel_kexec_load_disabled_action:testaction:1 - - - - Ensure the Default Bash Umask is Set Correctly - - ocil:ssg-accounts_umask_etc_bashrc_action:testaction:1 - - - - Verify Root Has A Primary GID 0 - - ocil:ssg-accounts_root_gid_zero_action:testaction:1 - - - - Configure auditd space_left on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_action:testaction:1 - - - - Remove tftp Daemon - - ocil:ssg-package_tftp_removed_action:testaction:1 - - - - Disable SSH Support for Rhosts RSA Authentication - - ocil:ssg-sshd_disable_rhosts_rsa_action:testaction:1 - - - - Verify Permissions on cron.daily - - ocil:ssg-file_permissions_cron_daily_action:testaction:1 - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_send_redirects_action:testaction:1 - - - - Configure a Sufficiently Large Partition for Audit Logs - - ocil:ssg-auditd_audispd_configure_sufficiently_large_partition_action:testaction:1 - - - - Verify that system commands files are group owned by root or a system account - - ocil:ssg-file_groupownership_system_commands_dirs_action:testaction:1 - - - - Uninstall dovecot Package - - ocil:ssg-package_dovecot_removed_action:testaction:1 - - - - Verify Permissions on group File - - ocil:ssg-file_permissions_etc_group_action:testaction:1 - - - - Ensure remote access methods are monitored in Rsyslog - - ocil:ssg-rsyslog_remote_access_monitoring_action:testaction:1 - - - - Verify that system commands directories have root as a group owner - - ocil:ssg-dir_system_commands_group_root_owned_action:testaction:1 - - - - Verify User Who Owns /etc/iptables Directory - - ocil:ssg-directory_owner_etc_iptables_action:testaction:1 - - - - Disable Core Dumps for SUID programs - - ocil:ssg-sysctl_fs_suid_dumpable_action:testaction:1 - - - - Audit Configuration Files Must Be Owned By Group root - - ocil:ssg-file_groupownership_audit_configuration_action:testaction:1 - - - - Disable Kerberos Authentication - - ocil:ssg-sshd_disable_kerb_auth_action:testaction:1 - - - - Disable storing core dump - - ocil:ssg-coredump_disable_storage_action:testaction:1 - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_route_localnet_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chage - - ocil:ssg-audit_rules_privileged_commands_chage_action:testaction:1 - - - - Disable IPv6 Networking Support Automatic Loading - - ocil:ssg-kernel_module_ipv6_option_disabled_action:testaction:1 - - - - Set Kernel Parameter to Increase Local Port Range - - ocil:ssg-sysctl_net_ipv4_ip_local_port_range_action:testaction:1 - - - - Enable the Hardware RNG Entropy Gatherer Service - - ocil:ssg-service_rngd_enabled_action:testaction:1 - - - - Enable the SSSD Service - - ocil:ssg-service_sssd_enabled_action:testaction:1 - - - - Disable TIPC Support - - ocil:ssg-kernel_module_tipc_disabled_action:testaction:1 - - - - Account Lockouts Must Be Logged - - ocil:ssg-accounts_passwords_pam_faillock_audit_action:testaction:1 - - - - Lock Accounts After Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_deny_action:testaction:1 - - - - Remove User Host-Based Authentication Files - - ocil:ssg-no_user_host_based_files_action:testaction:1 - - - - Record Any Attempts to Run setfacl - - ocil:ssg-audit_rules_execution_setfacl_action:testaction:1 - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts_action:testaction:1 - - - - Disable core dump backtraces - - ocil:ssg-coredump_disable_backtraces_action:testaction:1 - - - - Configure immutable Audit login UIDs - - ocil:ssg-audit_rules_immutable_login_uids_action:testaction:1 - - - - Restrict Exposed Kernel Pointer Addresses Access - - ocil:ssg-sysctl_kernel_kptr_restrict_action:testaction:1 - - - - Enable Use of Strict Mode Checking - - ocil:ssg-sshd_enable_strictmodes_action:testaction:1 - - - - Verify Owner on cron.deny - - ocil:ssg-file_owner_cron_deny_action:testaction:1 - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_shared_media_action:testaction:1 - - - - Set Password Warning Age - - ocil:ssg-accounts_password_warn_age_login_defs_action:testaction:1 - - - - Use Kerberos Security on All Exports - - ocil:ssg-use_kerberos_security_all_exports_action:testaction:1 - - - - Verify Group Who Owns Backup passwd File - - ocil:ssg-file_groupowner_backup_etc_passwd_action:testaction:1 - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_tcp_rfc1337_action:testaction:1 - - - - Mount Remote Filesystems with nodev - - ocil:ssg-mount_option_nodev_remote_filesystems_action:testaction:1 - - - - Ensure gpgcheck Enabled for All yum Package Repositories - - ocil:ssg-ensure_gpgcheck_never_disabled_action:testaction:1 - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty - - ocil:ssg-sudo_add_requiretty_action:testaction:1 - - - - Configure the deny_execmem SELinux Boolean - - ocil:ssg-sebool_deny_execmem_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - truncate - - ocil:ssg-audit_rules_unsuccessful_file_modification_truncate_action:testaction:1 - - - - Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - - ocil:ssg-dconf_gnome_disable_ctrlaltdel_reboot_action:testaction:1 - - - - Verify and Correct File Permissions with RPM - - ocil:ssg-rpm_verify_permissions_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudo - - ocil:ssg-audit_rules_privileged_commands_sudo_action:testaction:1 - - - - Force kernel panic on uncorrected MCEs - - ocil:ssg-grub2_mce_argument_action:testaction:1 - - - - Install rng-tools Package - - ocil:ssg-package_rng-tools_installed_action:testaction:1 - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_rp_filter_action:testaction:1 - - - - Disable SSH Support for .rhosts Files - - ocil:ssg-sshd_disable_rhosts_action:testaction:1 - - - - Set Interactive Session Timeout - - ocil:ssg-accounts_tmout_action:testaction:1 - - - - Set LogLevel to INFO - - ocil:ssg-sshd_set_loglevel_info_action:testaction:1 - - - - Configure auditing of successful ownership changes - - ocil:ssg-audit_owner_change_success_action:testaction:1 - - - - Distribute the SSH Server configuration to multiple files in a config directory. - - ocil:ssg-sshd_use_directory_configuration_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/security/opasswd - - ocil:ssg-audit_rules_usergroup_modification_opasswd_action:testaction:1 - - - - Verify Permissions On /etc/sestatus.conf File - - ocil:ssg-file_permissions_etc_sestatus_conf_action:testaction:1 - - - - Configure AIDE to Verify Extended Attributes - - ocil:ssg-aide_verify_ext_attributes_action:testaction:1 - - - - Set Existing Passwords Minimum Age - - ocil:ssg-accounts_password_set_min_life_existing_action:testaction:1 - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - ocil:ssg-auditd_data_retention_max_log_file_action_action:testaction:1 - - - - Configure System Cryptography Policy - - ocil:ssg-configure_crypto_policy_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - lastlog - - ocil:ssg-audit_rules_login_events_lastlog_action:testaction:1 - - - - IOMMU configuration directive - - ocil:ssg-grub2_enable_iommu_force_action:testaction:1 - - - - Disable /dev/kmem virtual device support - - ocil:ssg-kernel_config_devkmem_action:testaction:1 - - - - Ensure Chrony is only configured with the server directive - - ocil:ssg-chronyd_server_directive_action:testaction:1 - - - - Verify Permissions on /var/log/messages File - - ocil:ssg-file_permissions_var_log_messages_action:testaction:1 - - - - Set Password Minimum Age - - ocil:ssg-accounts_minimum_age_login_defs_action:testaction:1 - - - - Install libreswan Package - - ocil:ssg-package_libreswan_installed_action:testaction:1 - - - - Ensure debug-shell service is not enabled during boot - - ocil:ssg-grub2_systemd_debug-shell_argument_absent_action:testaction:1 - - - - Prevent non-Privileged Users from Modifying Network Interfaces using nmcli - - ocil:ssg-network_nmcli_permissions_action:testaction:1 - - - - Add nodev Option to /boot - - ocil:ssg-mount_option_boot_nodev_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Digit Characters - - ocil:ssg-accounts_password_pam_dcredit_action:testaction:1 - - - - Enable Public Key Authentication - - ocil:ssg-sshd_enable_pubkey_auth_action:testaction:1 - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - - ocil:ssg-sysctl_net_ipv4_conf_default_secure_redirects_action:testaction:1 - - - - Configure basic parameters of Audit system - - ocil:ssg-audit_basic_configuration_action:testaction:1 - - - - Add nodev Option to /home - - ocil:ssg-mount_option_home_nodev_action:testaction:1 - - - - Enable GNOME3 Screensaver Lock After Idle Period - - ocil:ssg-dconf_gnome_screensaver_lock_enabled_action:testaction:1 - - - - Enable page allocator poisoning - - ocil:ssg-grub2_page_poison_argument_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - - ocil:ssg-audit_rules_privileged_commands_sudoedit_action:testaction:1 - - - - Disable SCTP Support - - ocil:ssg-kernel_module_sctp_disabled_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - - ocil:ssg-audit_rules_sysadmin_actions_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchownat - - ocil:ssg-audit_rules_dac_modification_fchownat_action:testaction:1 - - - - Verify Owner on cron.d - - ocil:ssg-file_owner_cron_d_action:testaction:1 - - - - A remote time server for Chrony is configured - - ocil:ssg-chronyd_specify_remote_server_action:testaction:1 - - - - All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group - - ocil:ssg-accounts_users_home_files_groupownership_action:testaction:1 + ocil:ssg-account_password_pam_faillock_system_auth_action:testaction:1 @@ -245830,136 +264537,46 @@ fi ocil:ssg-account_password_selinux_faillock_dir_action:testaction:1 - - Verify Who Owns /etc/shells File + + Account Lockouts Must Be Logged - ocil:ssg-file_owner_etc_shells_action:testaction:1 + ocil:ssg-account_passwords_pam_faillock_audit_action:testaction:1 - - Verify All Account Password Hashes are Shadowed with SHA512 + + Account Lockouts Must Persist - ocil:ssg-accounts_password_all_shadowed_sha512_action:testaction:1 + ocil:ssg-account_passwords_pam_faillock_dir_action:testaction:1 - - Disable GDM Automatic Login + + Assign Expiration Date to Temporary Accounts - ocil:ssg-gnome_gdm_disable_automatic_login_action:testaction:1 + ocil:ssg-account_temp_expire_date_action:testaction:1 - - Set Password Maximum Age + + Ensure All Accounts on the System Have Unique User IDs - ocil:ssg-accounts_maximum_age_login_defs_action:testaction:1 + ocil:ssg-account_unique_id_action:testaction:1 - - Record Events that Modify the System's Discretionary Access Controls - fchmodat + + Ensure All Accounts on the System Have Unique Names - ocil:ssg-audit_rules_dac_modification_fchmodat_action:testaction:1 + ocil:ssg-account_unique_name_action:testaction:1 - - Don't define allowed commands in sudoers by means of exclusion + + Use Centralized and Automated Authentication - ocil:ssg-sudoers_no_command_negation_action:testaction:1 + ocil:ssg-account_use_centralized_automated_auth_action:testaction:1 - - Enable SLUB debugging support + + Only Authorized Local User Accounts Exist on Operating System - ocil:ssg-kernel_config_slub_debug_action:testaction:1 - - - - Verify that Interactive Boot is Disabled - - ocil:ssg-grub2_disable_interactive_boot_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Permissions - - ocil:ssg-file_permissions_user_cfg_action:testaction:1 - - - - Verify Permissions on shadow File - - ocil:ssg-file_permissions_etc_shadow_action:testaction:1 - - - - Configure auditing of successful file deletions - - ocil:ssg-audit_delete_success_action:testaction:1 - - - - Uninstall iprutils Package - - ocil:ssg-package_iprutils_removed_action:testaction:1 - - - - Limit sampling frequency of the Perf system - - ocil:ssg-sysctl_kernel_perf_event_max_sample_rate_action:testaction:1 - - - - Configure opensc Smart Card Drivers - - ocil:ssg-configure_opensc_card_drivers_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_source_route_action:testaction:1 - - - - Set existing passwords a period of inactivity before they been locked - - ocil:ssg-accounts_set_post_pw_existing_action:testaction:1 - - - - Disable kernel debugfs - - ocil:ssg-kernel_config_debug_fs_action:testaction:1 - - - - Verify the UEFI Boot Loader grub.cfg User Ownership - - ocil:ssg-file_owner_efi_grub2_cfg_action:testaction:1 - - - - Record Any Attempts to Run restorecon - - ocil:ssg-audit_rules_execution_restorecon_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - ftruncate - - ocil:ssg-audit_rules_unsuccessful_file_modification_ftruncate_action:testaction:1 - - - - Uninstall setroubleshoot-plugins Package - - ocil:ssg-package_setroubleshoot-plugins_removed_action:testaction:1 - - - - Disable DCCP Support - - ocil:ssg-kernel_module_dccp_disabled_action:testaction:1 + ocil:ssg-accounts_authorized_local_users_action:testaction:1 @@ -245968,40 +264585,142 @@ fi ocil:ssg-accounts_have_homedir_login_defs_action:testaction:1 - - Set SSH authentication attempt limit + + Ensure the Logon Failure Delay is Set Correctly in login.defs - ocil:ssg-sshd_set_max_auth_tries_action:testaction:1 + ocil:ssg-accounts_logon_fail_delay_action:testaction:1 - - Add nodev Option to Removable Media Partitions + + Limit the Number of Concurrent Login Sessions Allowed Per User - ocil:ssg-mount_option_nodev_removable_partitions_action:testaction:1 + ocil:ssg-accounts_max_concurrent_login_sessions_action:testaction:1 - - User Initialization Files Must Be Group-Owned By The Primary Group + + Set Password Maximum Age - ocil:ssg-accounts_user_dot_group_ownership_action:testaction:1 + ocil:ssg-accounts_maximum_age_login_defs_action:testaction:1 - - Verify User Who Owns /etc/nftables Directory + + Set Password Minimum Age - ocil:ssg-directory_owner_etc_nftables_action:testaction:1 + ocil:ssg-accounts_minimum_age_login_defs_action:testaction:1 - - Verify Group Who Owns Backup shadow File + + Verify Only Root Has UID 0 - ocil:ssg-file_owner_backup_etc_shadow_action:testaction:1 + ocil:ssg-accounts_no_uid_except_zero_action:testaction:1 - - Use zero for poisoning instead of debugging value + + Verify All Account Password Hashes are Shadowed - ocil:ssg-kernel_config_page_poisoning_zero_action:testaction:1 + ocil:ssg-accounts_password_all_shadowed_action:testaction:1 + + + + Verify All Account Password Hashes are Shadowed with SHA512 + + ocil:ssg-accounts_password_all_shadowed_sha512_action:testaction:1 + + + + Ensure all users last password change date is in the past + + ocil:ssg-accounts_password_last_change_is_in_past_action:testaction:1 + + + + Set Password Minimum Length in login.defs + + ocil:ssg-accounts_password_minlen_login_defs_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Digit Characters + + ocil:ssg-accounts_password_pam_dcredit_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words + + ocil:ssg-accounts_password_pam_dictcheck_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Different Characters + + ocil:ssg-accounts_password_pam_difok_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Enforce for root User + + ocil:ssg-accounts_password_pam_enforce_root_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + + ocil:ssg-accounts_password_pam_lcredit_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class + + ocil:ssg-accounts_password_pam_maxclassrepeat_action:testaction:1 + + + + Set Password Maximum Consecutive Repeating Characters + + ocil:ssg-accounts_password_pam_maxrepeat_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Different Categories + + ocil:ssg-accounts_password_pam_minclass_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Length + + ocil:ssg-accounts_password_pam_minlen_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Special Characters + + ocil:ssg-accounts_password_pam_ocredit_action:testaction:1 + + + + Limit Password Reuse: password-auth + + ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_action:testaction:1 + + + + Limit Password Reuse: system-auth + + ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_action:testaction:1 + + + + Ensure PAM password complexity module is enabled in password-auth + + ocil:ssg-accounts_password_pam_pwquality_password_auth_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session in /etc/security/pwquality.conf + + ocil:ssg-accounts_password_pam_pwquality_retry_action:testaction:1 @@ -246016,52 +264735,784 @@ fi ocil:ssg-accounts_password_pam_retry_action:testaction:1 - - Disable the authlogin_radius SELinux Boolean + + Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - ocil:ssg-sebool_authlogin_radius_action:testaction:1 + ocil:ssg-accounts_password_pam_ucredit_action:testaction:1 - - Verify User Who Owns /etc/sysctl.d Directory + + Limit Password Reuse - ocil:ssg-directory_owner_etc_sysctld_action:testaction:1 + ocil:ssg-accounts_password_pam_unix_remember_action:testaction:1 - - Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + + Set number of Password Hashing Rounds - password-auth - ocil:ssg-fapolicy_default_deny_action:testaction:1 + ocil:ssg-accounts_password_pam_unix_rounds_password_auth_action:testaction:1 - - Add nosuid Option to /var/log + + Set number of Password Hashing Rounds - system-auth - ocil:ssg-mount_option_var_log_nosuid_action:testaction:1 + ocil:ssg-accounts_password_pam_unix_rounds_system_auth_action:testaction:1 - - Ensure /home Located On Separate Partition + + Set Existing Passwords Maximum Age - ocil:ssg-partition_for_home_action:testaction:1 + ocil:ssg-accounts_password_set_max_life_existing_action:testaction:1 - - Mount Remote Filesystems with Kerberos Security + + Set Root Account Password Maximum Age - ocil:ssg-mount_option_krb_sec_remote_filesystems_action:testaction:1 + ocil:ssg-accounts_password_set_max_life_root_action:testaction:1 - - Configure Speculative Store Bypass Mitigation + + Set Existing Passwords Minimum Age - ocil:ssg-grub2_spec_store_bypass_disable_argument_action:testaction:1 + ocil:ssg-accounts_password_set_min_life_existing_action:testaction:1 - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + Set Existing Passwords Warning Age - ocil:ssg-sysctl_net_ipv4_conf_default_accept_redirects_action:testaction:1 + ocil:ssg-accounts_password_set_warn_age_existing_action:testaction:1 + + + + Set Password Warning Age + + ocil:ssg-accounts_password_warn_age_login_defs_action:testaction:1 + + + + Account Lockouts Must Be Logged + + ocil:ssg-accounts_passwords_pam_faillock_audit_action:testaction:1 + + + + Lock Accounts After Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_deny_action:testaction:1 + + + + Configure the root Account for Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_deny_root_action:testaction:1 + + + + Lock Accounts Must Persist + + ocil:ssg-accounts_passwords_pam_faillock_dir_action:testaction:1 + + + + Set Interval For Counting Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_interval_action:testaction:1 + + + + Set Lockout Time for Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_unlock_time_action:testaction:1 + + + + Configure Polyinstantiation of /tmp Directories + + ocil:ssg-accounts_polyinstantiated_tmp_action:testaction:1 + + + + Configure Polyinstantiation of /var/tmp Directories + + ocil:ssg-accounts_polyinstantiated_var_tmp_action:testaction:1 + + + + Verify Root Has A Primary GID 0 + + ocil:ssg-accounts_root_gid_zero_action:testaction:1 + + + + Ensure that Root's Path Does Not Include World or Group-Writable Directories + + ocil:ssg-accounts_root_path_dirs_no_write_action:testaction:1 + + + + Set existing passwords a period of inactivity before they been locked + + ocil:ssg-accounts_set_post_pw_existing_action:testaction:1 + + + + Set Interactive Session Timeout + + ocil:ssg-accounts_tmout_action:testaction:1 + + + + Ensure the Default Bash Umask is Set Correctly + + ocil:ssg-accounts_umask_etc_bashrc_action:testaction:1 + + + + Ensure the Default C Shell Umask is Set Correctly + + ocil:ssg-accounts_umask_etc_csh_cshrc_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly in login.defs + + ocil:ssg-accounts_umask_etc_login_defs_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly in /etc/profile + + ocil:ssg-accounts_umask_etc_profile_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly For Interactive Users + + ocil:ssg-accounts_umask_interactive_users_action:testaction:1 + + + + User Initialization Files Must Be Group-Owned By The Primary Group + + ocil:ssg-accounts_user_dot_group_ownership_action:testaction:1 + + + + User Initialization Files Must Not Run World-Writable Programs + + ocil:ssg-accounts_user_dot_no_world_writable_programs_action:testaction:1 + + + + User Initialization Files Must Be Owned By the Primary User + + ocil:ssg-accounts_user_dot_user_ownership_action:testaction:1 + + + + Ensure that Users Path Contains Only Local Directories + + ocil:ssg-accounts_user_home_paths_only_action:testaction:1 + + + + All Interactive Users Must Have A Home Directory Defined + + ocil:ssg-accounts_user_interactive_home_directory_defined_action:testaction:1 + + + + All Interactive Users Home Directories Must Exist + + ocil:ssg-accounts_user_interactive_home_directory_exists_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group + + ocil:ssg-accounts_users_home_files_groupownership_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Have a Valid Owner + + ocil:ssg-accounts_users_home_files_ownership_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive + + ocil:ssg-accounts_users_home_files_permissions_action:testaction:1 + + + + Ensure McAfee Endpoint Security for Linux (ENSL) is running + + ocil:ssg-agent_mfetpd_running_action:testaction:1 + + + + Build and Test AIDE Database + + ocil:ssg-aide_build_database_action:testaction:1 + + + + Configure AIDE to Verify the Audit Tools + + ocil:ssg-aide_check_audit_tools_action:testaction:1 + + + + Configure Periodic Execution of AIDE + + ocil:ssg-aide_periodic_cron_checking_action:testaction:1 + + + + Configure Notification of Post-AIDE Scan Details + + ocil:ssg-aide_scan_notification_action:testaction:1 + + + + Configure AIDE to Use FIPS 140-2 for Validating Hashes + + ocil:ssg-aide_use_fips_hashes_action:testaction:1 + + + + Configure AIDE to Verify Access Control Lists (ACLs) + + ocil:ssg-aide_verify_acls_action:testaction:1 + + + + Configure AIDE to Verify Extended Attributes + + ocil:ssg-aide_verify_ext_attributes_action:testaction:1 + + + + Configure auditing of unsuccessful file accesses + + ocil:ssg-audit_access_failed_action:testaction:1 + + + + Configure auditing of successful file accesses + + ocil:ssg-audit_access_success_action:testaction:1 + + + + Configure basic parameters of Audit system + + ocil:ssg-audit_basic_configuration_action:testaction:1 + + + + Configure auditing of unsuccessful file creations + + ocil:ssg-audit_create_failed_action:testaction:1 + + + + Configure auditing of successful file creations + + ocil:ssg-audit_create_success_action:testaction:1 + + + + Configure auditing of unsuccessful file deletions + + ocil:ssg-audit_delete_failed_action:testaction:1 + + + + Configure auditing of successful file deletions + + ocil:ssg-audit_delete_success_action:testaction:1 + + + + Configure immutable Audit login UIDs + + ocil:ssg-audit_immutable_login_uids_action:testaction:1 + + + + Configure auditing of unsuccessful file modifications + + ocil:ssg-audit_modify_failed_action:testaction:1 + + + + Configure auditing of successful file modifications + + ocil:ssg-audit_modify_success_action:testaction:1 + + + + Configure auditing of loading and unloading of kernel modules + + ocil:ssg-audit_module_load_action:testaction:1 + + + + Perform general configuration of Audit for OSPP + + ocil:ssg-audit_ospp_general_action:testaction:1 + + + + Configure auditing of unsuccessful ownership changes + + ocil:ssg-audit_owner_change_failed_action:testaction:1 + + + + Configure auditing of successful ownership changes + + ocil:ssg-audit_owner_change_success_action:testaction:1 + + + + Configure auditing of unsuccessful permission changes + + ocil:ssg-audit_perm_change_failed_action:testaction:1 + + + + Configure auditing of successful permission changes + + ocil:ssg-audit_perm_change_success_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - init + + ocil:ssg-audit_privileged_commands_init_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + + ocil:ssg-audit_privileged_commands_poweroff_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - reboot + + ocil:ssg-audit_privileged_commands_reboot_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + + ocil:ssg-audit_privileged_commands_shutdown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - chmod + + ocil:ssg-audit_rules_dac_modification_chmod_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - chown + + ocil:ssg-audit_rules_dac_modification_chown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchmod + + ocil:ssg-audit_rules_dac_modification_fchmod_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchmodat + + ocil:ssg-audit_rules_dac_modification_fchmodat_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchown + + ocil:ssg-audit_rules_dac_modification_fchown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchownat + + ocil:ssg-audit_rules_dac_modification_fchownat_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fremovexattr + + ocil:ssg-audit_rules_dac_modification_fremovexattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fsetxattr + + ocil:ssg-audit_rules_dac_modification_fsetxattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lchown + + ocil:ssg-audit_rules_dac_modification_lchown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lremovexattr + + ocil:ssg-audit_rules_dac_modification_lremovexattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lsetxattr + + ocil:ssg-audit_rules_dac_modification_lsetxattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - removexattr + + ocil:ssg-audit_rules_dac_modification_removexattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - setxattr + + ocil:ssg-audit_rules_dac_modification_setxattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - umount + + ocil:ssg-audit_rules_dac_modification_umount_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - umount2 + + ocil:ssg-audit_rules_dac_modification_umount2_action:testaction:1 + + + + Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ + + ocil:ssg-audit_rules_etc_cron_d_action:testaction:1 + + + + Record Any Attempts to Run chacl + + ocil:ssg-audit_rules_execution_chacl_action:testaction:1 + + + + Record Any Attempts to Run chcon + + ocil:ssg-audit_rules_execution_chcon_action:testaction:1 + + + + Record Any Attempts to Run restorecon + + ocil:ssg-audit_rules_execution_restorecon_action:testaction:1 + + + + Record Any Attempts to Run semanage + + ocil:ssg-audit_rules_execution_semanage_action:testaction:1 + + + + Record Any Attempts to Run setfacl + + ocil:ssg-audit_rules_execution_setfacl_action:testaction:1 + + + + Record Any Attempts to Run setfiles + + ocil:ssg-audit_rules_execution_setfiles_action:testaction:1 + + + + Record Any Attempts to Run setsebool + + ocil:ssg-audit_rules_execution_setsebool_action:testaction:1 + + + + Record Any Attempts to Run seunshare + + ocil:ssg-audit_rules_execution_seunshare_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User + + ocil:ssg-audit_rules_file_deletion_events_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - rename + + ocil:ssg-audit_rules_file_deletion_events_rename_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - renameat + + ocil:ssg-audit_rules_file_deletion_events_renameat_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - rmdir + + ocil:ssg-audit_rules_file_deletion_events_rmdir_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - unlink + + ocil:ssg-audit_rules_file_deletion_events_unlink_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - unlinkat + + ocil:ssg-audit_rules_file_deletion_events_unlinkat_action:testaction:1 + + + + Make the auditd Configuration Immutable + + ocil:ssg-audit_rules_immutable_action:testaction:1 + + + + Configure immutable Audit login UIDs + + ocil:ssg-audit_rules_immutable_login_uids_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading + + ocil:ssg-audit_rules_kernel_module_loading_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + + ocil:ssg-audit_rules_kernel_module_loading_delete_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + + ocil:ssg-audit_rules_kernel_module_loading_finit_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + + ocil:ssg-audit_rules_kernel_module_loading_init_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - faillock + + ocil:ssg-audit_rules_login_events_faillock_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - lastlog + + ocil:ssg-audit_rules_login_events_lastlog_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - tallylog + + ocil:ssg-audit_rules_login_events_tallylog_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls + + ocil:ssg-audit_rules_mac_modification_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + + ocil:ssg-audit_rules_mac_modification_etc_selinux_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + + ocil:ssg-audit_rules_mac_modification_usr_share_action:testaction:1 + + + + Ensure auditd Collects Information on Exporting to Media (successful) + + ocil:ssg-audit_rules_media_export_action:testaction:1 + + + + Record Events that Modify the System's Network Environment + + ocil:ssg-audit_rules_networkconfig_modification_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands + + ocil:ssg-audit_rules_privileged_commands_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - at + + ocil:ssg-audit_rules_privileged_commands_at_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chage + + ocil:ssg-audit_rules_privileged_commands_chage_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chsh + + ocil:ssg-audit_rules_privileged_commands_chsh_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - crontab + + ocil:ssg-audit_rules_privileged_commands_crontab_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + + ocil:ssg-audit_rules_privileged_commands_gpasswd_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - kmod + + ocil:ssg-audit_rules_privileged_commands_kmod_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - mount + + ocil:ssg-audit_rules_privileged_commands_mount_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + + ocil:ssg-audit_rules_privileged_commands_newgrp_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + + ocil:ssg-audit_rules_privileged_commands_pam_timestamp_check_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - passwd + + ocil:ssg-audit_rules_privileged_commands_passwd_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + + ocil:ssg-audit_rules_privileged_commands_postdrop_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + + ocil:ssg-audit_rules_privileged_commands_postqueue_action:testaction:1 + + + + Record Any Attempts to Run ssh-agent + + ocil:ssg-audit_rules_privileged_commands_ssh_agent_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + + ocil:ssg-audit_rules_privileged_commands_ssh_keysign_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - su + + ocil:ssg-audit_rules_privileged_commands_su_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudo + + ocil:ssg-audit_rules_privileged_commands_sudo_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + + ocil:ssg-audit_rules_privileged_commands_sudoedit_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - umount + + ocil:ssg-audit_rules_privileged_commands_umount_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + + ocil:ssg-audit_rules_privileged_commands_unix_chkpwd_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + + ocil:ssg-audit_rules_privileged_commands_unix_update_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + + ocil:ssg-audit_rules_privileged_commands_userhelper_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usermod + + ocil:ssg-audit_rules_privileged_commands_usermod_action:testaction:1 @@ -246070,4853 +265521,4486 @@ fi ocil:ssg-audit_rules_privileged_commands_usernetctl_action:testaction:1 + + Record Attempts to Alter Process and Session Initiation Information btmp + + ocil:ssg-audit_rules_session_events_btmp_action:testaction:1 + + + + Record Attempts to Alter Process and Session Initiation Information utmp + + ocil:ssg-audit_rules_session_events_utmp_action:testaction:1 + + + + Record Attempts to Alter Process and Session Initiation Information wtmp + + ocil:ssg-audit_rules_session_events_wtmp_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + + ocil:ssg-audit_rules_sudoers_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + + ocil:ssg-audit_rules_sudoers_d_action:testaction:1 + + + + Record Events When Privileged Executables Are Run + + ocil:ssg-audit_rules_suid_privilege_function_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions + + ocil:ssg-audit_rules_sysadmin_actions_action:testaction:1 + + + + Shutdown System When Auditing Failures Occur + + ocil:ssg-audit_rules_system_shutdown_action:testaction:1 + + + + Record attempts to alter time through adjtimex + + ocil:ssg-audit_rules_time_adjtimex_action:testaction:1 + + + + Record Attempts to Alter Time Through clock_settime + + ocil:ssg-audit_rules_time_clock_settime_action:testaction:1 + + + + Record attempts to alter time through settimeofday + + ocil:ssg-audit_rules_time_settimeofday_action:testaction:1 + + + + Record Attempts to Alter Time Through stime + + ocil:ssg-audit_rules_time_stime_action:testaction:1 + + + + Record Attempts to Alter the localtime File + + ocil:ssg-audit_rules_time_watch_localtime_action:testaction:1 + + + + Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) + + ocil:ssg-audit_rules_unsuccessful_file_modification_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - creat + + ocil:ssg-audit_rules_unsuccessful_file_modification_creat_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - ftruncate + + ocil:ssg-audit_rules_unsuccessful_file_modification_ftruncate_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - open + + ocil:ssg-audit_rules_unsuccessful_file_modification_open_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - open_by_handle_at + + ocil:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - openat + + ocil:ssg-audit_rules_unsuccessful_file_modification_openat_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - truncate + + ocil:ssg-audit_rules_unsuccessful_file_modification_truncate_action:testaction:1 + + + + Record Events that Modify User/Group Information + + ocil:ssg-audit_rules_usergroup_modification_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/group + + ocil:ssg-audit_rules_usergroup_modification_group_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/gshadow + + ocil:ssg-audit_rules_usergroup_modification_gshadow_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/security/opasswd + + ocil:ssg-audit_rules_usergroup_modification_opasswd_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/passwd + + ocil:ssg-audit_rules_usergroup_modification_passwd_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/shadow + + ocil:ssg-audit_rules_usergroup_modification_shadow_action:testaction:1 + + + + Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron + + ocil:ssg-audit_rules_var_spool_cron_action:testaction:1 + + + + Record Attempts to perform maintenance activities + + ocil:ssg-audit_sudo_log_events_action:testaction:1 + + + + Configure a Sufficiently Large Partition for Audit Logs + + ocil:ssg-auditd_audispd_configure_sufficiently_large_partition_action:testaction:1 + + + + Configure auditd to use audispd's syslog plugin + + ocil:ssg-auditd_audispd_syslog_plugin_activated_action:testaction:1 + + + + Configure auditd Disk Error Action on Disk Error + + ocil:ssg-auditd_data_disk_error_action_action:testaction:1 + + + + Configure auditd Disk Error Action on Disk Error + + ocil:ssg-auditd_data_disk_error_action_stig_action:testaction:1 + + + + Configure auditd Disk Full Action when Disk Space Is Full + + ocil:ssg-auditd_data_disk_full_action_action:testaction:1 + + + + Configure auditd Disk Full Action when Disk Space Is Full + + ocil:ssg-auditd_data_disk_full_action_stig_action:testaction:1 + + + + Configure auditd mail_acct Action on Low Disk Space + + ocil:ssg-auditd_data_retention_action_mail_acct_action:testaction:1 + + + + Configure auditd admin_space_left Action on Low Disk Space + + ocil:ssg-auditd_data_retention_admin_space_left_action_action:testaction:1 + + + + Configure auditd admin_space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_admin_space_left_percentage_action:testaction:1 + + + + Configure auditd flush priority + + ocil:ssg-auditd_data_retention_flush_action:testaction:1 + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + ocil:ssg-auditd_data_retention_max_log_file_action_action:testaction:1 + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + ocil:ssg-auditd_data_retention_max_log_file_action_stig_action:testaction:1 + + + + Configure auditd space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_action:testaction:1 + + + + Configure auditd space_left Action on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_action_action:testaction:1 + + + + Configure auditd space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_percentage_action:testaction:1 + + + + Set number of records to cause an explicit flush to audit logs + + ocil:ssg-auditd_freq_action:testaction:1 + + + + Include Local Events in Audit Logs + + ocil:ssg-auditd_local_events_action:testaction:1 + + + + Resolve information before writing to audit logs + + ocil:ssg-auditd_log_format_action:testaction:1 + + + + Set type of computer node name logging in audit logs + + ocil:ssg-auditd_name_format_action:testaction:1 + + + + Appropriate Action Must be Setup When the Internal Audit Event Queue is Full + + ocil:ssg-auditd_overflow_action_action:testaction:1 + + + + Write Audit Logs to the Disk + + ocil:ssg-auditd_write_logs_action:testaction:1 + + + + Modify the System Login Banner + + ocil:ssg-banner_etc_issue_action:testaction:1 + + + + Modify the System Login Banner for Remote Connections + + ocil:ssg-banner_etc_issue_net_action:testaction:1 + + + + Modify the System Message of the Day Banner + + ocil:ssg-banner_etc_motd_action:testaction:1 + + + + Enable NX or XD Support in the BIOS + + ocil:ssg-bios_enable_execution_restrictions_action:testaction:1 + + + + Disable chrony daemon from acting as server + + ocil:ssg-chronyd_client_only_action:testaction:1 + + + + Chrony Configure Pool and Server + + ocil:ssg-chronyd_configure_pool_and_server_action:testaction:1 + + + + Disable network management of chrony daemon + + ocil:ssg-chronyd_no_chronyc_network_action:testaction:1 + + + + Configure Time Service Maxpoll Interval + + ocil:ssg-chronyd_or_ntpd_set_maxpoll_action:testaction:1 + + + + Ensure that chronyd is running under chrony user account + + ocil:ssg-chronyd_run_as_chrony_user_action:testaction:1 + + + + Ensure Chrony is only configured with the server directive + + ocil:ssg-chronyd_server_directive_action:testaction:1 + + + + A remote time server for Chrony is configured + + ocil:ssg-chronyd_specify_remote_server_action:testaction:1 + + + + Ensure yum Removes Previous Package Versions + + ocil:ssg-clean_components_post_updating_action:testaction:1 + + + + Configure BIND to use System Crypto Policy + + ocil:ssg-configure_bind_crypto_policy_action:testaction:1 + + + + Configure System Cryptography Policy + + ocil:ssg-configure_crypto_policy_action:testaction:1 + + + + Configure the Firewalld Ports + + ocil:ssg-configure_firewalld_ports_action:testaction:1 + + + + Configure Kerberos to use System Crypto Policy + + ocil:ssg-configure_kerberos_crypto_policy_action:testaction:1 + + + + Configure Libreswan to use System Crypto Policy + + ocil:ssg-configure_libreswan_crypto_policy_action:testaction:1 + + + + Configure opensc Smart Card Drivers + + ocil:ssg-configure_opensc_card_drivers_action:testaction:1 + + + + Configure OpenSSL library to use System Crypto Policy + + ocil:ssg-configure_openssl_crypto_policy_action:testaction:1 + + + + Configure SSH to use System Crypto Policy + + ocil:ssg-configure_ssh_crypto_policy_action:testaction:1 + + + + Log USBGuard daemon audit events using Linux Audit + + ocil:ssg-configure_usbguard_auditbackend_action:testaction:1 + + + + Configure Backups of User Data + + ocil:ssg-configure_user_data_backups_action:testaction:1 + + + + Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems + + ocil:ssg-configured_firewalld_default_deny_action:testaction:1 + + + + Disable core dump backtraces + + ocil:ssg-coredump_disable_backtraces_action:testaction:1 + + + + Disable storing core dump + + ocil:ssg-coredump_disable_storage_action:testaction:1 + + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles + + ocil:ssg-dconf_db_up_to_date_action:testaction:1 + + + + Enable GNOME3 Login Warning Banner + + ocil:ssg-dconf_gnome_banner_enabled_action:testaction:1 + + + + Disable GNOME3 Automounting + + ocil:ssg-dconf_gnome_disable_automount_action:testaction:1 + + + + Disable GNOME3 Automount Opening + + ocil:ssg-dconf_gnome_disable_automount_open_action:testaction:1 + + + + Disable GNOME3 Automount running + + ocil:ssg-dconf_gnome_disable_autorun_action:testaction:1 + + + + Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 + + ocil:ssg-dconf_gnome_disable_ctrlaltdel_reboot_action:testaction:1 + + + + Disable the GNOME3 Login Restart and Shutdown Buttons + + ocil:ssg-dconf_gnome_disable_restart_shutdown_action:testaction:1 + + + + Disable the GNOME3 Login User List + + ocil:ssg-dconf_gnome_disable_user_list_action:testaction:1 + + + + Enable the GNOME3 Screen Locking On Smartcard Removal + + ocil:ssg-dconf_gnome_lock_screen_on_smartcard_removal_action:testaction:1 + + + + Set the GNOME3 Login Warning Banner Text + + ocil:ssg-dconf_gnome_login_banner_text_action:testaction:1 + + + + Require Credential Prompting for Remote Access in GNOME3 + + ocil:ssg-dconf_gnome_remote_access_credential_prompt_action:testaction:1 + + + + Require Encryption for Remote Access in GNOME3 + + ocil:ssg-dconf_gnome_remote_access_encryption_action:testaction:1 + + + + Enable GNOME3 Screensaver Idle Activation + + ocil:ssg-dconf_gnome_screensaver_idle_activation_enabled_action:testaction:1 + + + + Set GNOME3 Screensaver Inactivity Timeout + + ocil:ssg-dconf_gnome_screensaver_idle_delay_action:testaction:1 + + + + Set GNOME3 Screensaver Lock Delay After Activation Period + + ocil:ssg-dconf_gnome_screensaver_lock_delay_action:testaction:1 + + + + Enable GNOME3 Screensaver Lock After Idle Period + + ocil:ssg-dconf_gnome_screensaver_lock_enabled_action:testaction:1 + + + + Implement Blank Screensaver + + ocil:ssg-dconf_gnome_screensaver_mode_blank_action:testaction:1 + + + + Ensure Users Cannot Change GNOME3 Screensaver Settings + + ocil:ssg-dconf_gnome_screensaver_user_locks_action:testaction:1 + + + + Ensure Users Cannot Change GNOME3 Session Idle Settings + + ocil:ssg-dconf_gnome_session_idle_user_locks_action:testaction:1 + + + + Verify that Shared Library Directories Have Root Group Ownership + + ocil:ssg-dir_group_ownership_library_dirs_action:testaction:1 + + + + Verify that System Executable Have Root Ownership + + ocil:ssg-dir_ownership_binary_dirs_action:testaction:1 + + + + Verify that Shared Library Directories Have Root Ownership + + ocil:ssg-dir_ownership_library_dirs_action:testaction:1 + + + + Verify that System Executable Directories Have Restrictive Permissions + + ocil:ssg-dir_permissions_binary_dirs_action:testaction:1 + + + + Verify that Shared Library Directories Have Restrictive Permissions + + ocil:ssg-dir_permissions_library_dirs_action:testaction:1 + + + + Ensure All World-Writable Directories Are Owned by root User + + ocil:ssg-dir_perms_world_writable_root_owned_action:testaction:1 + + + + Verify that All World-Writable Directories Have Sticky Bits Set + + ocil:ssg-dir_perms_world_writable_sticky_bits_action:testaction:1 + + + + Verify that system commands directories have root as a group owner + + ocil:ssg-dir_system_commands_group_root_owned_action:testaction:1 + + + + Verify that system commands directories have root ownership + + ocil:ssg-dir_system_commands_root_owned_action:testaction:1 + + + + Record Access Events to Audit Log Directory + + ocil:ssg-directory_access_var_log_audit_action:testaction:1 + + + + System Audit Directories Must Be Group Owned By Root + + ocil:ssg-directory_group_ownership_var_log_audit_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.d Directory + + ocil:ssg-directory_groupowner_etc_ipsecd_action:testaction:1 + + + + Verify Group Who Owns /etc/iptables Directory + + ocil:ssg-directory_groupowner_etc_iptables_action:testaction:1 + + + + Verify Group Who Owns /etc/nftables Directory + + ocil:ssg-directory_groupowner_etc_nftables_action:testaction:1 + + + + Verify Group Who Owns /etc/selinux Directory + + ocil:ssg-directory_groupowner_etc_selinux_action:testaction:1 + + + + Verify Group Who Owns /etc/sudoers.d Directory + + ocil:ssg-directory_groupowner_etc_sudoersd_action:testaction:1 + + + + Verify Group Who Owns /etc/sysctl.d Directory + + ocil:ssg-directory_groupowner_etc_sysctld_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.d Directory + + ocil:ssg-directory_owner_etc_ipsecd_action:testaction:1 + + + + Verify User Who Owns /etc/iptables Directory + + ocil:ssg-directory_owner_etc_iptables_action:testaction:1 + + + + Verify User Who Owns /etc/nftables Directory + + ocil:ssg-directory_owner_etc_nftables_action:testaction:1 + + + + Verify User Who Owns /etc/selinux Directory + + ocil:ssg-directory_owner_etc_selinux_action:testaction:1 + + + + Verify User Who Owns /etc/sudoers.d Directory + + ocil:ssg-directory_owner_etc_sudoersd_action:testaction:1 + + + + Verify User Who Owns /etc/sysctl.d Directory + + ocil:ssg-directory_owner_etc_sysctld_action:testaction:1 + + + + System Audit Directories Must Be Owned By Root + + ocil:ssg-directory_ownership_var_log_audit_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.d Directory + + ocil:ssg-directory_permissions_etc_ipsecd_action:testaction:1 + + + + Verify Permissions On /etc/iptables Directory + + ocil:ssg-directory_permissions_etc_iptables_action:testaction:1 + + + + Verify Permissions On /etc/nftables Directory + + ocil:ssg-directory_permissions_etc_nftables_action:testaction:1 + + + + Verify Permissions On /etc/selinux Directory + + ocil:ssg-directory_permissions_etc_selinux_action:testaction:1 + + + + Verify Permissions On /etc/sudoers.d Directory + + ocil:ssg-directory_permissions_etc_sudoersd_action:testaction:1 + + + + Verify Permissions On /etc/sysctl.d Directory + + ocil:ssg-directory_permissions_etc_sysctld_action:testaction:1 + + + + System Audit Logs Must Have Mode 0750 or Less Permissive + + ocil:ssg-directory_permissions_var_log_audit_action:testaction:1 + + + + Disable Ctrl-Alt-Del Burst Action + + ocil:ssg-disable_ctrlaltdel_burstaction_action:testaction:1 + + + + Disable Ctrl-Alt-Del Reboot Activation + + ocil:ssg-disable_ctrlaltdel_reboot_action:testaction:1 + + + + Disable Host-Based Authentication + + ocil:ssg-disable_host_auth_action:testaction:1 + + + + Disable Core Dumps for All Users + + ocil:ssg-disable_users_coredumps_action:testaction:1 + + Disallow Configuration to Bypass Password Requirements for Privilege Escalation ocil:ssg-disallow_bypass_password_sudo_action:testaction:1 + + Ensure PAM Displays Last Logon/Access Notification + + ocil:ssg-display_login_attempts_action:testaction:1 + + + + Configure dnf-automatic to Install Available Updates Automatically + + ocil:ssg-dnf-automatic_apply_updates_action:testaction:1 + + + + Configure dnf-automatic to Install Only Security Updates + + ocil:ssg-dnf-automatic_security_updates_only_action:testaction:1 + + + + Enable authselect + + ocil:ssg-enable_authselect_action:testaction:1 + + + + Configure GNOME3 DConf User Profile + + ocil:ssg-enable_dconf_user_profile_action:testaction:1 + + + + Enable Dracut FIPS Module + + ocil:ssg-enable_dracut_fips_module_action:testaction:1 + + + + Enable FIPS Mode + + ocil:ssg-enable_fips_mode_action:testaction:1 + + + + Encrypt Partitions + + ocil:ssg-encrypt_partitions_action:testaction:1 + + + + Ensure EPEL Repository is Disabled + + ocil:ssg-ensure_epel_repos_disabled_action:testaction:1 + + + + Ensure gpgcheck Enabled In Main yum Configuration + + ocil:ssg-ensure_gpgcheck_globally_activated_action:testaction:1 + + + + Ensure gpgcheck Enabled for Local Packages + + ocil:ssg-ensure_gpgcheck_local_packages_action:testaction:1 + + + + Ensure gpgcheck Enabled for All yum Package Repositories + + ocil:ssg-ensure_gpgcheck_never_disabled_action:testaction:1 + + + + Ensure Logrotate Runs Periodically + + ocil:ssg-ensure_logrotate_activated_action:testaction:1 + + + + Ensure Oracle Linux GPG Key Installed + + ocil:ssg-ensure_oracle_gpgkey_installed_action:testaction:1 + + + + Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty + + ocil:ssg-ensure_pam_wheel_group_empty_action:testaction:1 + + + + Ensure Authentication Required for Single User Mode + + ocil:ssg-ensure_root_password_configured_action:testaction:1 + + + + Ensure '/etc/system-fips' exists + + ocil:ssg-etc_system_fips_exists_action:testaction:1 + + + + Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + + ocil:ssg-fapolicy_default_deny_action:testaction:1 + + + + Ensure that /etc/at.deny does not exist + + ocil:ssg-file_at_deny_not_exist_action:testaction:1 + + + + Audit Tools Must Be Group-owned by Root + + ocil:ssg-file_audit_tools_group_ownership_action:testaction:1 + + + + Audit Tools Must Be Owned by Root + + ocil:ssg-file_audit_tools_ownership_action:testaction:1 + + + + Audit Tools Must Have a Mode of 0755 or Less Permissive + + ocil:ssg-file_audit_tools_permissions_action:testaction:1 + + + + Ensure that /etc/cron.deny does not exist + + ocil:ssg-file_cron_deny_not_exist_action:testaction:1 + + + + System Audit Logs Must Be Group Owned By Root + + ocil:ssg-file_group_ownership_var_log_audit_action:testaction:1 + + + + Verify Group Who Owns /etc/at.allow file + + ocil:ssg-file_groupowner_at_allow_action:testaction:1 + + + + Verify Group Who Owns Backup group File + + ocil:ssg-file_groupowner_backup_etc_group_action:testaction:1 + + + + Verify Group Who Owns Backup gshadow File + + ocil:ssg-file_groupowner_backup_etc_gshadow_action:testaction:1 + + + + Verify Group Who Owns Backup passwd File + + ocil:ssg-file_groupowner_backup_etc_passwd_action:testaction:1 + + + + Verify User Who Owns Backup shadow File + + ocil:ssg-file_groupowner_backup_etc_shadow_action:testaction:1 + + + + Verify Group Who Owns /etc/cron.allow file + + ocil:ssg-file_groupowner_cron_allow_action:testaction:1 + + + + Verify Group Who Owns cron.d + + ocil:ssg-file_groupowner_cron_d_action:testaction:1 + + + + Verify Group Who Owns cron.daily + + ocil:ssg-file_groupowner_cron_daily_action:testaction:1 + + + + Verify Group Who Owns cron.deny + + ocil:ssg-file_groupowner_cron_deny_action:testaction:1 + + + + Verify Group Who Owns cron.hourly + + ocil:ssg-file_groupowner_cron_hourly_action:testaction:1 + + + + Verify Group Who Owns cron.monthly + + ocil:ssg-file_groupowner_cron_monthly_action:testaction:1 + + + + Verify Group Who Owns cron.weekly + + ocil:ssg-file_groupowner_cron_weekly_action:testaction:1 + + + + Verify Group Who Owns Crontab + + ocil:ssg-file_groupowner_crontab_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Group Ownership + + ocil:ssg-file_groupowner_efi_user_cfg_action:testaction:1 + + + + Verify Group Who Owns /etc/chrony.keys File + + ocil:ssg-file_groupowner_etc_chrony_keys_action:testaction:1 + + + + Verify Group Who Owns /etc/crypttab File + + ocil:ssg-file_groupowner_etc_crypttab_action:testaction:1 + + + + Verify Group Who Owns group File + + ocil:ssg-file_groupowner_etc_group_action:testaction:1 + + + + Verify Group Who Owns gshadow File + + ocil:ssg-file_groupowner_etc_gshadow_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.conf File + + ocil:ssg-file_groupowner_etc_ipsec_conf_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.secrets File + + ocil:ssg-file_groupowner_etc_ipsec_secrets_action:testaction:1 + + + + Verify Group Ownership of System Login Banner for Remote Connections + + ocil:ssg-file_groupowner_etc_issue_net_action:testaction:1 + + + + Verify Group Who Owns passwd File + + ocil:ssg-file_groupowner_etc_passwd_action:testaction:1 + + + + Verify Group Who Owns /etc/sestatus.conf File + + ocil:ssg-file_groupowner_etc_sestatus_conf_action:testaction:1 + + + + Verify Group Who Owns shadow File + + ocil:ssg-file_groupowner_etc_shadow_action:testaction:1 + + + + Verify Group Who Owns /etc/shells File + + ocil:ssg-file_groupowner_etc_shells_action:testaction:1 + + + + Verify Group Who Owns /etc/sudoers File + + ocil:ssg-file_groupowner_etc_sudoers_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg Group Ownership + + ocil:ssg-file_groupowner_grub2_cfg_action:testaction:1 + + + + Verify Group Who Owns SSH Server config file + + ocil:ssg-file_groupowner_sshd_config_action:testaction:1 + + + + Verify Group Who Owns System.map Files + + ocil:ssg-file_groupowner_systemmap_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Group Ownership + + ocil:ssg-file_groupowner_user_cfg_action:testaction:1 + + + + Verify Group Who Owns /var/log Directory + + ocil:ssg-file_groupowner_var_log_action:testaction:1 + + + + Verify Group Who Owns /var/log/messages File + + ocil:ssg-file_groupowner_var_log_messages_action:testaction:1 + + + + Verify Group Who Owns /var/log/syslog File + + ocil:ssg-file_groupowner_var_log_syslog_action:testaction:1 + + + + Audit Configuration Files Must Be Owned By Group root + + ocil:ssg-file_groupownership_audit_configuration_action:testaction:1 + + + + All Interactive User Home Directories Must Be Group-Owned By The Primary Group + + ocil:ssg-file_groupownership_home_directories_action:testaction:1 + + + + Verify Group Ownership on SSH Server Private *_key Key Files + + ocil:ssg-file_groupownership_sshd_private_key_action:testaction:1 + + + + Verify Group Ownership on SSH Server Public *.pub Key Files + + ocil:ssg-file_groupownership_sshd_pub_key_action:testaction:1 + + + + Verify that system commands files are group owned by root or a system account + + ocil:ssg-file_groupownership_system_commands_dirs_action:testaction:1 + + + + Verify User Who Owns Backup group File + + ocil:ssg-file_owner_backup_etc_group_action:testaction:1 + + + + Verify User Who Owns Backup gshadow File + + ocil:ssg-file_owner_backup_etc_gshadow_action:testaction:1 + + + + Verify User Who Owns Backup passwd File + + ocil:ssg-file_owner_backup_etc_passwd_action:testaction:1 + + + + Verify Group Who Owns Backup shadow File + + ocil:ssg-file_owner_backup_etc_shadow_action:testaction:1 + + + + Verify User Who Owns /etc/cron.allow file + + ocil:ssg-file_owner_cron_allow_action:testaction:1 + + + + Verify Owner on cron.d + + ocil:ssg-file_owner_cron_d_action:testaction:1 + + + + Verify Owner on cron.daily + + ocil:ssg-file_owner_cron_daily_action:testaction:1 + + + + Verify Owner on cron.deny + + ocil:ssg-file_owner_cron_deny_action:testaction:1 + + + + Verify Owner on cron.hourly + + ocil:ssg-file_owner_cron_hourly_action:testaction:1 + + + + Verify Owner on cron.monthly + + ocil:ssg-file_owner_cron_monthly_action:testaction:1 + + + + Verify Owner on cron.weekly + + ocil:ssg-file_owner_cron_weekly_action:testaction:1 + + + + Verify Owner on crontab + + ocil:ssg-file_owner_crontab_action:testaction:1 + + + + Verify User Who Owns /etc/chrony.keys File + + ocil:ssg-file_owner_etc_chrony_keys_action:testaction:1 + + + + Verify User Who Owns /etc/crypttab File + + ocil:ssg-file_owner_etc_crypttab_action:testaction:1 + + + + Verify User Who Owns group File + + ocil:ssg-file_owner_etc_group_action:testaction:1 + + + + Verify User Who Owns gshadow File + + ocil:ssg-file_owner_etc_gshadow_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.conf File + + ocil:ssg-file_owner_etc_ipsec_conf_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.secrets File + + ocil:ssg-file_owner_etc_ipsec_secrets_action:testaction:1 + + + + Verify ownership of System Login Banner for Remote Connections + + ocil:ssg-file_owner_etc_issue_net_action:testaction:1 + + + + Verify User Who Owns passwd File + + ocil:ssg-file_owner_etc_passwd_action:testaction:1 + + + + Verify User Who Owns /etc/sestatus.conf File + + ocil:ssg-file_owner_etc_sestatus_conf_action:testaction:1 + + + + Verify User Who Owns shadow File + + ocil:ssg-file_owner_etc_shadow_action:testaction:1 + + + + Verify Who Owns /etc/shells File + + ocil:ssg-file_owner_etc_shells_action:testaction:1 + + + + Verify User Who Owns /etc/sudoers File + + ocil:ssg-file_owner_etc_sudoers_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg User Ownership + + ocil:ssg-file_owner_grub2_cfg_action:testaction:1 + + + + Verify Owner on SSH Server config file + + ocil:ssg-file_owner_sshd_config_action:testaction:1 + + + + Verify User Who Owns System.map Files + + ocil:ssg-file_owner_systemmap_action:testaction:1 + + + + Verify /boot/grub2/user.cfg User Ownership + + ocil:ssg-file_owner_user_cfg_action:testaction:1 + + + + Verify User Who Owns /var/log Directory + + ocil:ssg-file_owner_var_log_action:testaction:1 + + + + Verify User Who Owns /var/log/messages File + + ocil:ssg-file_owner_var_log_messages_action:testaction:1 + + + + Verify User Who Owns /var/log/syslog File + + ocil:ssg-file_owner_var_log_syslog_action:testaction:1 + + + + Audit Configuration Files Must Be Owned By Root + + ocil:ssg-file_ownership_audit_configuration_action:testaction:1 + + + + Verify that System Executables Have Root Ownership + + ocil:ssg-file_ownership_binary_dirs_action:testaction:1 + + + + Verify that Shared Library Files Have Root Ownership + + ocil:ssg-file_ownership_library_dirs_action:testaction:1 + + + + Verify Ownership on SSH Server Private *_key Key Files + + ocil:ssg-file_ownership_sshd_private_key_action:testaction:1 + + Verify Ownership on SSH Server Public *.pub Key Files ocil:ssg-file_ownership_sshd_pub_key_action:testaction:1 + + System Audit Logs Must Be Owned By Root + + ocil:ssg-file_ownership_var_log_audit_action:testaction:1 + + + + Ensure All User Initialization Files Have Mode 0740 Or Less Permissive + + ocil:ssg-file_permission_user_init_files_action:testaction:1 + + + + Verify Permissions on /etc/at.allow file + + ocil:ssg-file_permissions_at_allow_action:testaction:1 + + + + Audit Configuration Files Permissions are 640 or More Restrictive + + ocil:ssg-file_permissions_audit_configuration_action:testaction:1 + + + + Verify Permissions on Backup group File + + ocil:ssg-file_permissions_backup_etc_group_action:testaction:1 + + + + Verify Permissions on Backup gshadow File + + ocil:ssg-file_permissions_backup_etc_gshadow_action:testaction:1 + + + + Verify Permissions on Backup passwd File + + ocil:ssg-file_permissions_backup_etc_passwd_action:testaction:1 + + + + Verify Permissions on Backup shadow File + + ocil:ssg-file_permissions_backup_etc_shadow_action:testaction:1 + + + + Verify that System Executables Have Restrictive Permissions + + ocil:ssg-file_permissions_binary_dirs_action:testaction:1 + + + + Verify Permissions on /etc/cron.allow file + + ocil:ssg-file_permissions_cron_allow_action:testaction:1 + + + + Verify Permissions on cron.d + + ocil:ssg-file_permissions_cron_d_action:testaction:1 + + + + Verify Permissions on cron.daily + + ocil:ssg-file_permissions_cron_daily_action:testaction:1 + + + + Verify Permissions on cron.hourly + + ocil:ssg-file_permissions_cron_hourly_action:testaction:1 + + + + Verify Permissions on cron.monthly + + ocil:ssg-file_permissions_cron_monthly_action:testaction:1 + + + + Verify Permissions on cron.weekly + + ocil:ssg-file_permissions_cron_weekly_action:testaction:1 + + + + Verify Permissions on crontab + + ocil:ssg-file_permissions_crontab_action:testaction:1 + + + + Verify Permissions on /etc/audit/auditd.conf + + ocil:ssg-file_permissions_etc_audit_auditd_action:testaction:1 + + + + Verify Permissions on /etc/audit/rules.d/*.rules + + ocil:ssg-file_permissions_etc_audit_rulesd_action:testaction:1 + + + + Verify Permissions On /etc/chrony.keys File + + ocil:ssg-file_permissions_etc_chrony_keys_action:testaction:1 + + + + Verify Permissions On /etc/crypttab File + + ocil:ssg-file_permissions_etc_crypttab_action:testaction:1 + + + + Verify Permissions on group File + + ocil:ssg-file_permissions_etc_group_action:testaction:1 + + + + Verify Permissions on gshadow File + + ocil:ssg-file_permissions_etc_gshadow_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.conf File + + ocil:ssg-file_permissions_etc_ipsec_conf_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.secrets File + + ocil:ssg-file_permissions_etc_ipsec_secrets_action:testaction:1 + + + + Verify permissions on System Login Banner for Remote Connections + + ocil:ssg-file_permissions_etc_issue_net_action:testaction:1 + + + + Verify Permissions on passwd File + + ocil:ssg-file_permissions_etc_passwd_action:testaction:1 + + + + Verify Permissions On /etc/sestatus.conf File + + ocil:ssg-file_permissions_etc_sestatus_conf_action:testaction:1 + + + + Verify Permissions on shadow File + + ocil:ssg-file_permissions_etc_shadow_action:testaction:1 + + + + Verify Permissions on /etc/shells File + + ocil:ssg-file_permissions_etc_shells_action:testaction:1 + + + + Verify Permissions On /etc/sudoers File + + ocil:ssg-file_permissions_etc_sudoers_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg Permissions + + ocil:ssg-file_permissions_grub2_cfg_action:testaction:1 + + + + All Interactive User Home Directories Must Have mode 0750 Or Less Permissive + + ocil:ssg-file_permissions_home_directories_action:testaction:1 + + + + Ensure that User Home Directories are not Group-Writable or World-Readable + + ocil:ssg-file_permissions_home_dirs_action:testaction:1 + + + + Verify that Shared Library Files Have Restrictive Permissions + + ocil:ssg-file_permissions_library_dirs_action:testaction:1 + + + + Verify Permissions on SSH Server config file + + ocil:ssg-file_permissions_sshd_config_action:testaction:1 + + + + Verify Permissions on SSH Server Private *_key Key Files + + ocil:ssg-file_permissions_sshd_private_key_action:testaction:1 + + + + Verify Permissions on SSH Server Public *.pub Key Files + + ocil:ssg-file_permissions_sshd_pub_key_action:testaction:1 + + + + Verify Permissions on System.map Files + + ocil:ssg-file_permissions_systemmap_action:testaction:1 + + + + Ensure All SGID Executables Are Authorized + + ocil:ssg-file_permissions_unauthorized_sgid_action:testaction:1 + + + + Ensure All SUID Executables Are Authorized + + ocil:ssg-file_permissions_unauthorized_suid_action:testaction:1 + + + + Ensure No World-Writable Files Exist + + ocil:ssg-file_permissions_unauthorized_world_writable_action:testaction:1 + + + + Ensure All Files Are Owned by a Group + + ocil:ssg-file_permissions_ungroupowned_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Permissions + + ocil:ssg-file_permissions_user_cfg_action:testaction:1 + + + + Verify Permissions on /var/log Directory + + ocil:ssg-file_permissions_var_log_action:testaction:1 + + + + System Audit Logs Must Have Mode 0640 or Less Permissive + + ocil:ssg-file_permissions_var_log_audit_action:testaction:1 + + + + Verify Permissions on /var/log/messages File + + ocil:ssg-file_permissions_var_log_messages_action:testaction:1 + + + + Verify Permissions on /var/log/syslog File + + ocil:ssg-file_permissions_var_log_syslog_action:testaction:1 + + + + System Wide Crypto Policy Files Must Point to FIPS Policy + + ocil:ssg-fips_crypto_policy_symlinks_action:testaction:1 + + + + Configure Firewalld to Use the Nftables Backend + + ocil:ssg-firewalld-backend_action:testaction:1 + + + + Configure Firewalld to Restrict Loopback Traffic + + ocil:ssg-firewalld_loopback_traffic_restricted_action:testaction:1 + + + + Configure Firewalld to Trust Loopback Traffic + + ocil:ssg-firewalld_loopback_traffic_trusted_action:testaction:1 + + + + Enable SSH Server firewalld Firewall Exception + + ocil:ssg-firewalld_sshd_port_enabled_action:testaction:1 + + + + All GIDs referenced in /etc/passwd must be defined in /etc/group + + ocil:ssg-gid_passwd_group_same_action:testaction:1 + + + + Disable GDM Automatic Login + + ocil:ssg-gnome_gdm_disable_automatic_login_action:testaction:1 + + + + Disable XDMCP in GDM + + ocil:ssg-gnome_gdm_disable_xdmcp_action:testaction:1 + + + + Ensure All Groups on the System Have Unique Group ID + + ocil:ssg-group_unique_id_action:testaction:1 + + + + Set the Boot Loader Admin Username to a Non-Default Value + + ocil:ssg-grub2_admin_username_action:testaction:1 + + + + Enable Auditing for Processes Which Start Prior to the Audit Daemon + + ocil:ssg-grub2_audit_argument_action:testaction:1 + + + + Extend Audit Backlog Limit for the Audit Daemon + + ocil:ssg-grub2_audit_backlog_limit_argument_action:testaction:1 + + + + Verify that Interactive Boot is Disabled + + ocil:ssg-grub2_disable_interactive_boot_action:testaction:1 + + + + Disable Recovery Booting + + ocil:ssg-grub2_disable_recovery_action:testaction:1 + + + + IOMMU configuration directive + + ocil:ssg-grub2_enable_iommu_force_action:testaction:1 + + + + Ensure SELinux Not Disabled in /etc/default/grub + + ocil:ssg-grub2_enable_selinux_action:testaction:1 + + + + Configure kernel to zero out memory before allocation + + ocil:ssg-grub2_init_on_alloc_argument_action:testaction:1 + + + + Configure L1 Terminal Fault mitigations + + ocil:ssg-grub2_l1tf_argument_action:testaction:1 + + + + Force kernel panic on uncorrected MCEs + + ocil:ssg-grub2_mce_argument_action:testaction:1 + + + + Configure Microarchitectural Data Sampling mitigation + + ocil:ssg-grub2_mds_argument_action:testaction:1 + + + + Ensure SMAP is not disabled during boot + + ocil:ssg-grub2_nosmap_argument_absent_action:testaction:1 + + + + Ensure SMEP is not disabled during boot + + ocil:ssg-grub2_nosmep_argument_absent_action:testaction:1 + + + + Enable randomization of the page allocator + + ocil:ssg-grub2_page_alloc_shuffle_argument_action:testaction:1 + + + + Enable page allocator poisoning + + ocil:ssg-grub2_page_poison_argument_action:testaction:1 + + + + Set Boot Loader Password in grub2 + + ocil:ssg-grub2_password_action:testaction:1 + + + + Enable Kernel Page-Table Isolation (KPTI) + + ocil:ssg-grub2_pti_argument_action:testaction:1 + + + + Configure the confidence in TPM for entropy + + ocil:ssg-grub2_rng_core_default_quality_argument_action:testaction:1 + + + + Disable merging of slabs with similar size + + ocil:ssg-grub2_slab_nomerge_argument_action:testaction:1 + + + + Enable SLUB/SLAB allocator poisoning + + ocil:ssg-grub2_slub_debug_argument_action:testaction:1 + + + + Configure Speculative Store Bypass Mitigation + + ocil:ssg-grub2_spec_store_bypass_disable_argument_action:testaction:1 + + + + Enforce Spectre v2 mitigation + + ocil:ssg-grub2_spectre_v2_argument_action:testaction:1 + + + + Ensure debug-shell service is not enabled during boot + + ocil:ssg-grub2_systemd_debug-shell_argument_absent_action:testaction:1 + + + + Disable vsyscalls + + ocil:ssg-grub2_vsyscall_argument_action:testaction:1 + + + + Harden SSH client Crypto Policy + + ocil:ssg-harden_ssh_client_crypto_policy_action:testaction:1 + + + + Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config + + ocil:ssg-harden_sshd_ciphers_openssh_conf_crypto_policy_action:testaction:1 + + + + Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config + + ocil:ssg-harden_sshd_ciphers_opensshserver_conf_crypto_policy_action:testaction:1 + + + + Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config + + ocil:ssg-harden_sshd_macs_openssh_conf_crypto_policy_action:testaction:1 + + + + Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config + + ocil:ssg-harden_sshd_macs_opensshserver_conf_crypto_policy_action:testaction:1 + + + + Install Smart Card Packages For Multifactor Authentication + + ocil:ssg-install_smartcard_packages_action:testaction:1 + + + + The Installed Operating System Is Vendor Supported + + ocil:ssg-installed_OS_is_vendor_supported_action:testaction:1 + + + + Do not allow ACPI methods to be inserted/replaced at run time + + ocil:ssg-kernel_config_acpi_custom_method_action:testaction:1 + + + + Emulate Privileged Access Never (PAN) + + ocil:ssg-kernel_config_arm64_sw_ttbr0_pan_action:testaction:1 + + + + Disable kernel support for MISC binaries + + ocil:ssg-kernel_config_binfmt_misc_action:testaction:1 + + + + Enable support for BUG() + + ocil:ssg-kernel_config_bug_action:testaction:1 + + + + Trigger a kernel BUG when data corruption is detected + + ocil:ssg-kernel_config_bug_on_data_corruption_action:testaction:1 + + + + Disable compatibility with brk() + + ocil:ssg-kernel_config_compat_brk_action:testaction:1 + + + + Disable the 32-bit vDSO + + ocil:ssg-kernel_config_compat_vdso_action:testaction:1 + + + + Enable checks on credential management + + ocil:ssg-kernel_config_debug_credentials_action:testaction:1 + + + + Disable kernel debugfs + + ocil:ssg-kernel_config_debug_fs_action:testaction:1 + + + + Enable checks on linked list manipulation + + ocil:ssg-kernel_config_debug_list_action:testaction:1 + + + + Enable checks on notifier call chains + + ocil:ssg-kernel_config_debug_notifiers_action:testaction:1 + + + + Enable checks on scatter-gather (SG) table operations + + ocil:ssg-kernel_config_debug_sg_action:testaction:1 + + + + Warn on W+X mappings found at boot + + ocil:ssg-kernel_config_debug_wx_action:testaction:1 + + + + Configure Low Address Space To Protect From User Allocation + + ocil:ssg-kernel_config_default_mmap_min_addr_action:testaction:1 + + + + Disable /dev/kmem virtual device support + + ocil:ssg-kernel_config_devkmem_action:testaction:1 + + + + Harden common str/mem functions against buffer overflows + + ocil:ssg-kernel_config_fortify_source_action:testaction:1 + + + + Generate some entropy during boot and runtime + + ocil:ssg-kernel_config_gcc_plugin_latent_entropy_action:testaction:1 + + + + Randomize layout of sensitive kernel structures + + ocil:ssg-kernel_config_gcc_plugin_randstruct_action:testaction:1 + + + + Poison kernel stack before returning from syscalls + + ocil:ssg-kernel_config_gcc_plugin_stackleak_action:testaction:1 + + + + Force initialization of variables containing userspace addresses + + ocil:ssg-kernel_config_gcc_plugin_structleak_action:testaction:1 + + + + zero-init everything passed by reference + + ocil:ssg-kernel_config_gcc_plugin_structleak_byref_all_action:testaction:1 + + + + Harden memory copies between kernel and userspace + + ocil:ssg-kernel_config_hardened_usercopy_action:testaction:1 + + + + Do not allow usercopy whitelist violations to fallback to object size + + ocil:ssg-kernel_config_hardened_usercopy_fallback_action:testaction:1 + + + + Disable hibernation + + ocil:ssg-kernel_config_hibernation_action:testaction:1 + + + + Disable IA32 emulation + + ocil:ssg-kernel_config_ia32_emulation_action:testaction:1 + + + + Disable the IPv6 protocol + + ocil:ssg-kernel_config_ipv6_action:testaction:1 + + + + Disable kexec system call + + ocil:ssg-kernel_config_kexec_action:testaction:1 + + + + Disable legacy (BSD) PTY support + + ocil:ssg-kernel_config_legacy_ptys_action:testaction:1 + + + + Disable vsyscall emulation + + ocil:ssg-kernel_config_legacy_vsyscall_emulate_action:testaction:1 + + + + Disable vsyscall mapping + + ocil:ssg-kernel_config_legacy_vsyscall_none_action:testaction:1 + + + + Disable vsyscall emulate execution only + + ocil:ssg-kernel_config_legacy_vsyscall_xonly_action:testaction:1 + + + + Disable the LDT (local descriptor table) + + ocil:ssg-kernel_config_modify_ldt_syscall_action:testaction:1 + + + + Enable module signature verification + + ocil:ssg-kernel_config_module_sig_action:testaction:1 + + + + Enable automatic signing of all modules + + ocil:ssg-kernel_config_module_sig_all_action:testaction:1 + + + + Require modules to be validly signed + + ocil:ssg-kernel_config_module_sig_force_action:testaction:1 + + + + Specify the hash to use when signing modules + + ocil:ssg-kernel_config_module_sig_hash_action:testaction:1 + + + + Specify module signing key to use + + ocil:ssg-kernel_config_module_sig_key_action:testaction:1 + + + + Sign kernel modules with SHA-512 + + ocil:ssg-kernel_config_module_sig_sha512_action:testaction:1 + + + + Enable poison of pages after freeing + + ocil:ssg-kernel_config_page_poisoning_action:testaction:1 + + + + Enable poison without sanity check + + ocil:ssg-kernel_config_page_poisoning_no_sanity_action:testaction:1 + + + + Use zero for poisoning instead of debugging value + + ocil:ssg-kernel_config_page_poisoning_zero_action:testaction:1 + + + + Remove the kernel mapping in user mode + + ocil:ssg-kernel_config_page_table_isolation_action:testaction:1 + + + + Kernel panic oops + + ocil:ssg-kernel_config_panic_on_oops_action:testaction:1 + + + + Kernel panic timeout + + ocil:ssg-kernel_config_panic_timeout_action:testaction:1 + + + + Disable support for /proc/kkcore + + ocil:ssg-kernel_config_proc_kcore_action:testaction:1 + + + + Randomize the address of the kernel image (KASLR) + + ocil:ssg-kernel_config_randomize_base_action:testaction:1 + + + + Randomize the kernel memory sections + + ocil:ssg-kernel_config_randomize_memory_action:testaction:1 + + + + Perform full reference count validation + + ocil:ssg-kernel_config_refcount_full_action:testaction:1 + + + + Avoid speculative indirect branches in kernel + + ocil:ssg-kernel_config_retpoline_action:testaction:1 + + + + Detect stack corruption on calls to schedule() + + ocil:ssg-kernel_config_sched_stack_end_check_action:testaction:1 + + + + Enable seccomp to safely compute untrusted bytecode + + ocil:ssg-kernel_config_seccomp_action:testaction:1 + + + + Enable use of Berkeley Packet Filter with seccomp + + ocil:ssg-kernel_config_seccomp_filter_action:testaction:1 + + + + Enable different security models + + ocil:ssg-kernel_config_security_action:testaction:1 + + + + Restrict unprivileged access to the kernel syslog + + ocil:ssg-kernel_config_security_dmesg_restrict_action:testaction:1 + + + + Disable mutable hooks + + ocil:ssg-kernel_config_security_writable_hooks_action:testaction:1 + + + + Enable Yama support + + ocil:ssg-kernel_config_security_yama_action:testaction:1 + + + + Harden slab freelist metadata + + ocil:ssg-kernel_config_slab_freelist_hardened_action:testaction:1 + + + + Randomize slab freelist + + ocil:ssg-kernel_config_slab_freelist_random_action:testaction:1 + + + + Disallow merge of slab caches + + ocil:ssg-kernel_config_slab_merge_default_action:testaction:1 + + + + Enable SLUB debugging support + + ocil:ssg-kernel_config_slub_debug_action:testaction:1 + + + + Stack Protector buffer overflow detection + + ocil:ssg-kernel_config_stackprotector_action:testaction:1 + + + + Strong Stack Protector + + ocil:ssg-kernel_config_stackprotector_strong_action:testaction:1 + + + + Make the kernel text and rodata read-only + + ocil:ssg-kernel_config_strict_kernel_rwx_action:testaction:1 + + + + Make the module text and rodata read-only + + ocil:ssg-kernel_config_strict_module_rwx_action:testaction:1 + + + + Enable TCP/IP syncookie support + + ocil:ssg-kernel_config_syn_cookies_action:testaction:1 + + + + Unmap kernel when running in userspace (aka KAISER) + + ocil:ssg-kernel_config_unmap_kernel_at_el0_action:testaction:1 + + + + User a virtually-mapped stack + + ocil:ssg-kernel_config_vmap_stack_action:testaction:1 + + + + Disable x86 vsyscall emulation + + ocil:ssg-kernel_config_x86_vsyscall_emulation_action:testaction:1 + + + + Disable ATM Support + + ocil:ssg-kernel_module_atm_disabled_action:testaction:1 + + + + Disable Bluetooth Kernel Module + + ocil:ssg-kernel_module_bluetooth_disabled_action:testaction:1 + + + + Disable CAN Support + + ocil:ssg-kernel_module_can_disabled_action:testaction:1 + + + + Disable Mounting of cramfs + + ocil:ssg-kernel_module_cramfs_disabled_action:testaction:1 + + + + Disable DCCP Support + + ocil:ssg-kernel_module_dccp_disabled_action:testaction:1 + + + + Disable IEEE 1394 (FireWire) Support + + ocil:ssg-kernel_module_firewire-core_disabled_action:testaction:1 + + + + Disable IPv6 Networking Support Automatic Loading + + ocil:ssg-kernel_module_ipv6_option_disabled_action:testaction:1 + + + + Disable RDS Support + + ocil:ssg-kernel_module_rds_disabled_action:testaction:1 + + + + Disable SCTP Support + + ocil:ssg-kernel_module_sctp_disabled_action:testaction:1 + + + + Disable TIPC Support + + ocil:ssg-kernel_module_tipc_disabled_action:testaction:1 + + + + Disable Modprobe Loading of USB Storage Driver + + ocil:ssg-kernel_module_usb-storage_disabled_action:testaction:1 + + + + Disable the uvcvideo module + + ocil:ssg-kernel_module_uvcvideo_disabled_action:testaction:1 + + + + Verify Any Configured IPSec Tunnel Connections + + ocil:ssg-libreswan_approved_tunnels_action:testaction:1 + + + + Configure Logind to terminate idle sessions after certain time of inactivity + + ocil:ssg-logind_session_timeout_action:testaction:1 + + + + Add nosuid Option to /boot/efi + + ocil:ssg-mount_option_boot_efi_nosuid_action:testaction:1 + + + + Add nodev Option to /boot + + ocil:ssg-mount_option_boot_nodev_action:testaction:1 + + + + Add noexec Option to /boot + + ocil:ssg-mount_option_boot_noexec_action:testaction:1 + + + + Add nosuid Option to /boot + + ocil:ssg-mount_option_boot_nosuid_action:testaction:1 + + + + Add nodev Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_nodev_action:testaction:1 + + + + Add noexec Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_noexec_action:testaction:1 + + + + Add nosuid Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_nosuid_action:testaction:1 + + + + Add grpquota Option to /home + + ocil:ssg-mount_option_home_grpquota_action:testaction:1 + + + + Add nodev Option to /home + + ocil:ssg-mount_option_home_nodev_action:testaction:1 + + + + Add noexec Option to /home + + ocil:ssg-mount_option_home_noexec_action:testaction:1 + + + + Add nosuid Option to /home + + ocil:ssg-mount_option_home_nosuid_action:testaction:1 + + + + Add usrquota Option to /home + + ocil:ssg-mount_option_home_usrquota_action:testaction:1 + + + + Mount Remote Filesystems with Kerberos Security + + ocil:ssg-mount_option_krb_sec_remote_filesystems_action:testaction:1 + + + + Add nodev Option to Non-Root Local Partitions + + ocil:ssg-mount_option_nodev_nonroot_local_partitions_action:testaction:1 + + + + Mount Remote Filesystems with nodev + + ocil:ssg-mount_option_nodev_remote_filesystems_action:testaction:1 + + + + Add nodev Option to Removable Media Partitions + + ocil:ssg-mount_option_nodev_removable_partitions_action:testaction:1 + + + + Mount Remote Filesystems with noexec + + ocil:ssg-mount_option_noexec_remote_filesystems_action:testaction:1 + + + + Add noexec Option to Removable Media Partitions + + ocil:ssg-mount_option_noexec_removable_partitions_action:testaction:1 + + + + Mount Remote Filesystems with nosuid + + ocil:ssg-mount_option_nosuid_remote_filesystems_action:testaction:1 + + + + Add nosuid Option to Removable Media Partitions + + ocil:ssg-mount_option_nosuid_removable_partitions_action:testaction:1 + + + + Add nosuid Option to /opt + + ocil:ssg-mount_option_opt_nosuid_action:testaction:1 + + + + Add nosuid Option to /srv + + ocil:ssg-mount_option_srv_nosuid_action:testaction:1 + + + + Add nodev Option to /tmp + + ocil:ssg-mount_option_tmp_nodev_action:testaction:1 + + + + Add noexec Option to /tmp + + ocil:ssg-mount_option_tmp_noexec_action:testaction:1 + + + + Add nosuid Option to /tmp + + ocil:ssg-mount_option_tmp_nosuid_action:testaction:1 + + + + Add nodev Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_nodev_action:testaction:1 + + + + Add noexec Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_noexec_action:testaction:1 + + + + Add nosuid Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_nosuid_action:testaction:1 + + + + Add nodev Option to /var/log + + ocil:ssg-mount_option_var_log_nodev_action:testaction:1 + + + + Add noexec Option to /var/log + + ocil:ssg-mount_option_var_log_noexec_action:testaction:1 + + + + Add nosuid Option to /var/log + + ocil:ssg-mount_option_var_log_nosuid_action:testaction:1 + + + + Add nodev Option to /var + + ocil:ssg-mount_option_var_nodev_action:testaction:1 + + + + Add noexec Option to /var + + ocil:ssg-mount_option_var_noexec_action:testaction:1 + + + + Add nosuid Option to /var + + ocil:ssg-mount_option_var_nosuid_action:testaction:1 + + + + Add nodev Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_nodev_action:testaction:1 + + + + Add noexec Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_noexec_action:testaction:1 + + + + Add nosuid Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_nosuid_action:testaction:1 + + + + Configure Multiple DNS Servers in /etc/resolv.conf + + ocil:ssg-network_configure_name_resolution_action:testaction:1 + + + + Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + + ocil:ssg-network_nmcli_permissions_action:testaction:1 + + + + Ensure System is Not Acting as a Network Sniffer + + ocil:ssg-network_sniffer_disabled_action:testaction:1 + + + + NetworkManager DNS Mode Must Be Must Configured + + ocil:ssg-networkmanager_dns_mode_action:testaction:1 + + + + Ensure All-Squashing Disabled On All Exports + + ocil:ssg-no_all_squash_exports_action:testaction:1 + + + + Direct root Logins Not Allowed + + ocil:ssg-no_direct_root_logins_action:testaction:1 + + + + Prevent Login to Accounts With Empty Password + + ocil:ssg-no_empty_passwords_action:testaction:1 + + + + Ensure There Are No Accounts With Blank or Null Passwords + + ocil:ssg-no_empty_passwords_etc_shadow_action:testaction:1 + + + + Ensure All Files Are Owned by a User + + ocil:ssg-no_files_unowned_by_user_action:testaction:1 + + + + Remove Host-Based Authentication Files + + ocil:ssg-no_host_based_files_action:testaction:1 + + + + Verify No netrc Files Exist + + ocil:ssg-no_netrc_files_action:testaction:1 + + + + Ensure that System Accounts Are Locked + + ocil:ssg-no_password_auth_for_systemaccounts_action:testaction:1 + + + + Remove Rsh Trust Files + + ocil:ssg-no_rsh_trust_files_action:testaction:1 + + + + Ensure that System Accounts Do Not Run a Shell Upon Login + + ocil:ssg-no_shelllogin_for_systemaccounts_action:testaction:1 + + + + Remove User Host-Based Authentication Files + + ocil:ssg-no_user_host_based_files_action:testaction:1 + + + + Install AIDE + + ocil:ssg-package_aide_installed_action:testaction:1 + + + + Install audispd-plugins Package + + ocil:ssg-package_audispd-plugins_installed_action:testaction:1 + + + + Ensure the audit Subsystem is Installed + + ocil:ssg-package_audit_installed_action:testaction:1 + + + + Uninstall bind Package + + ocil:ssg-package_bind_removed_action:testaction:1 + + + + The Chrony package is installed + + ocil:ssg-package_chrony_installed_action:testaction:1 + + + + Install the cron service + + ocil:ssg-package_cron_installed_action:testaction:1 + + + + Install crypto-policies package + + ocil:ssg-package_crypto-policies_installed_action:testaction:1 + + + + Install cryptsetup Package + + ocil:ssg-package_cryptsetup-luks_installed_action:testaction:1 + + + + Uninstall cyrus-imapd Package + + ocil:ssg-package_cyrus-imapd_removed_action:testaction:1 + + + + Uninstall DHCP Server Package + + ocil:ssg-package_dhcp_removed_action:testaction:1 + + + + Install dnf-automatic Package + + ocil:ssg-package_dnf-automatic_installed_action:testaction:1 + + + + Uninstall dovecot Package + + ocil:ssg-package_dovecot_removed_action:testaction:1 + + + + Install fapolicyd Package + + ocil:ssg-package_fapolicyd_installed_action:testaction:1 + + + + Install firewalld Package + + ocil:ssg-package_firewalld_installed_action:testaction:1 + + + + Remove ftp Package + + ocil:ssg-package_ftp_removed_action:testaction:1 + + + + Ensure gnutls-utils is installed + + ocil:ssg-package_gnutls-utils_installed_action:testaction:1 + + + + Uninstall gssproxy Package + + ocil:ssg-package_gssproxy_removed_action:testaction:1 + + + + Uninstall iprutils Package + + ocil:ssg-package_iprutils_removed_action:testaction:1 + + + + Install libreswan Package + + ocil:ssg-package_libreswan_installed_action:testaction:1 + + + + Install libselinux Package + + ocil:ssg-package_libselinux_installed_action:testaction:1 + + + + Ensure logrotate is Installed + + ocil:ssg-package_logrotate_installed_action:testaction:1 + + + + Install McAfee Endpoint Security for Linux (ENSL) + + ocil:ssg-package_mcafeetp_installed_action:testaction:1 + + + + Uninstall net-snmp Package + + ocil:ssg-package_net-snmp_removed_action:testaction:1 + + + + Uninstall nfs-utils Package + + ocil:ssg-package_nfs-utils_removed_action:testaction:1 + + + + Install nftables Package + + ocil:ssg-package_nftables_installed_action:testaction:1 + + + + Ensure nss-tools is installed + + ocil:ssg-package_nss-tools_installed_action:testaction:1 + + + + Install the opensc Package For Multifactor Authentication + + ocil:ssg-package_opensc_installed_action:testaction:1 + + + + Install openscap-scanner Package + + ocil:ssg-package_openscap-scanner_installed_action:testaction:1 + + + + Install OpenSSH client software + + ocil:ssg-package_openssh-clients_installed_action:testaction:1 + + + + Install the OpenSSH Server Package + + ocil:ssg-package_openssh-server_installed_action:testaction:1 + + + + Remove the OpenSSH Server Package + + ocil:ssg-package_openssh-server_removed_action:testaction:1 + + + + Install the pcsc-lite package + + ocil:ssg-package_pcsc-lite_installed_action:testaction:1 + + + + Install policycoreutils-python-utils package + + ocil:ssg-package_policycoreutils-python-utils_installed_action:testaction:1 + + + + Install policycoreutils Package + + ocil:ssg-package_policycoreutils_installed_action:testaction:1 + + + + The Postfix package is installed + + ocil:ssg-package_postfix_installed_action:testaction:1 + + + + Uninstall quagga Package + + ocil:ssg-package_quagga_removed_action:testaction:1 + + + + Install rear Package + + ocil:ssg-package_rear_installed_action:testaction:1 + + + + Install rng-tools Package + + ocil:ssg-package_rng-tools_installed_action:testaction:1 + + + + Ensure rsyslog-gnutls is installed + + ocil:ssg-package_rsyslog-gnutls_installed_action:testaction:1 + + + + Ensure rsyslog is Installed + + ocil:ssg-package_rsyslog_installed_action:testaction:1 + + + + The s-nail Package Is Installed + + ocil:ssg-package_s-nail_installed_action:testaction:1 + + + + Install scap-security-guide Package + + ocil:ssg-package_scap-security-guide_installed_action:testaction:1 + + + + Uninstall Sendmail Package + + ocil:ssg-package_sendmail_removed_action:testaction:1 + + + + Uninstall setroubleshoot-plugins Package + + ocil:ssg-package_setroubleshoot-plugins_removed_action:testaction:1 + + + + Uninstall setroubleshoot-server Package + + ocil:ssg-package_setroubleshoot-server_removed_action:testaction:1 + + + + Uninstall squid Package + + ocil:ssg-package_squid_removed_action:testaction:1 + + + + Install the SSSD Package + + ocil:ssg-package_sssd_installed_action:testaction:1 + + + + Install sudo Package + + ocil:ssg-package_sudo_installed_action:testaction:1 + + + + Ensure syslog-ng is Installed + + ocil:ssg-package_syslogng_installed_action:testaction:1 + + + + Uninstall telnet-server Package + + ocil:ssg-package_telnet-server_removed_action:testaction:1 + + + + Remove telnet Clients + + ocil:ssg-package_telnet_removed_action:testaction:1 + + + + Uninstall tftp-server Package + + ocil:ssg-package_tftp-server_removed_action:testaction:1 + + + + Remove tftp Daemon + + ocil:ssg-package_tftp_removed_action:testaction:1 + + + + Uninstall tuned Package + + ocil:ssg-package_tuned_removed_action:testaction:1 + + + + Install usbguard Package + + ocil:ssg-package_usbguard_installed_action:testaction:1 + + + + Uninstall vsftpd Package + + ocil:ssg-package_vsftpd_removed_action:testaction:1 + + + + Remove the X Windows Package Group + + ocil:ssg-package_xorg-x11-server-common_removed_action:testaction:1 + + + + Ensure /dev/shm is configured + + ocil:ssg-partition_for_dev_shm_action:testaction:1 + + + + Ensure /home Located On Separate Partition + + ocil:ssg-partition_for_home_action:testaction:1 + + + + Ensure /srv Located On Separate Partition + + ocil:ssg-partition_for_srv_action:testaction:1 + + + + Ensure /tmp Located On Separate Partition + + ocil:ssg-partition_for_tmp_action:testaction:1 + + + + Ensure /var Located On Separate Partition + + ocil:ssg-partition_for_var_action:testaction:1 + + + + Ensure /var/log Located On Separate Partition + + ocil:ssg-partition_for_var_log_action:testaction:1 + + + + Ensure /var/log/audit Located On Separate Partition + + ocil:ssg-partition_for_var_log_audit_action:testaction:1 + + + + Ensure /var/tmp Located On Separate Partition + + ocil:ssg-partition_for_var_tmp_action:testaction:1 + + + + Configure System to Forward All Mail For The Root Account + + ocil:ssg-postfix_client_configure_mail_alias_action:testaction:1 + + + + Configure System to Forward All Mail From Postmaster to The Root Account + + ocil:ssg-postfix_client_configure_mail_alias_postmaster_action:testaction:1 + + + + Configure System to Forward All Mail through a specific host + + ocil:ssg-postfix_client_configure_relayhost_action:testaction:1 + + + + Disable Postfix Network Listening + + ocil:ssg-postfix_network_listening_disabled_action:testaction:1 + + + + Prevent Unrestricted Mail Relaying + + ocil:ssg-postfix_prevent_unrestricted_relay_action:testaction:1 + + + + Prefer to use a 64-bit Operating System when supported + + ocil:ssg-prefer_64bit_os_action:testaction:1 + + + + Require Authentication for Emergency Systemd Target + + ocil:ssg-require_emergency_target_auth_action:testaction:1 + + + + Require Authentication for Single User Mode + + ocil:ssg-require_singleuser_auth_action:testaction:1 + + + + Restrict Serial Port Root Logins + + ocil:ssg-restrict_serial_port_logins_action:testaction:1 + + + + Verify the system-wide library files in directories +"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. + + ocil:ssg-root_permissions_syslibrary_files_action:testaction:1 + + + + Verify crypto-policies with RPM + + ocil:ssg-rpm_verify_crypto_policies_action:testaction:1 + + + + Verify File Hashes with RPM + + ocil:ssg-rpm_verify_hashes_action:testaction:1 + + + + Verify and Correct Ownership with RPM + + ocil:ssg-rpm_verify_ownership_action:testaction:1 + + + + Verify and Correct File Permissions with RPM + + ocil:ssg-rpm_verify_permissions_action:testaction:1 + + + + Ensure cron Is Logging To Rsyslog + + ocil:ssg-rsyslog_cron_logging_action:testaction:1 + + + + Ensure Rsyslog Authenticates Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdriverauthmode_action:testaction:1 + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdrivermode_action:testaction:1 + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_defaultnetstreamdriver_action:testaction:1 + + + + Ensure Log Files Are Owned By Appropriate Group + + ocil:ssg-rsyslog_files_groupownership_action:testaction:1 + + + + Ensure Log Files Are Owned By Appropriate User + + ocil:ssg-rsyslog_files_ownership_action:testaction:1 + + + + Ensure System Log Files Have Correct Permissions + + ocil:ssg-rsyslog_files_permissions_action:testaction:1 + + + + Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + + ocil:ssg-rsyslog_nolisten_action:testaction:1 + + + + Ensure remote access methods are monitored in Rsyslog + + ocil:ssg-rsyslog_remote_access_monitoring_action:testaction:1 + + + + Ensure Logs Sent To Remote Host + + ocil:ssg-rsyslog_remote_loghost_action:testaction:1 + + + + Configure TLS for rsyslog remote logging + + ocil:ssg-rsyslog_remote_tls_action:testaction:1 + + + + Configure CA certificate for rsyslog remote logging + + ocil:ssg-rsyslog_remote_tls_cacert_action:testaction:1 + + + + Enable the auditadm_exec_content SELinux Boolean + + ocil:ssg-sebool_auditadm_exec_content_action:testaction:1 + + + + Disable the authlogin_nsswitch_use_ldap SELinux Boolean + + ocil:ssg-sebool_authlogin_nsswitch_use_ldap_action:testaction:1 + + + + Disable the authlogin_radius SELinux Boolean + + ocil:ssg-sebool_authlogin_radius_action:testaction:1 + + + + Configure the deny_execmem SELinux Boolean + + ocil:ssg-sebool_deny_execmem_action:testaction:1 + + + + Enable the kerberos_enabled SELinux Boolean + + ocil:ssg-sebool_kerberos_enabled_action:testaction:1 + + + + Configure the polyinstantiation_enabled SELinux Boolean + + ocil:ssg-sebool_polyinstantiation_enabled_action:testaction:1 + + + + Configure the secure_mode_insmod SELinux Boolean + + ocil:ssg-sebool_secure_mode_insmod_action:testaction:1 + + + + Disable the selinuxuser_execheap SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execheap_action:testaction:1 + + + + Enable the selinuxuser_execmod SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execmod_action:testaction:1 + + + + Disable the selinuxuser_execstack SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execstack_action:testaction:1 + + + + Disable the ssh_sysadm_login SELinux Boolean + + ocil:ssg-sebool_ssh_sysadm_login_action:testaction:1 + + + + Ensure that Secure Boot is enabled + + ocil:ssg-secure_boot_enabled_action:testaction:1 + + + + Restrict Virtual Console Root Logins + + ocil:ssg-securetty_root_login_console_only_action:testaction:1 + + + + Ensure Software Patches Installed + + ocil:ssg-security_patches_up_to_date_action:testaction:1 + + + + Ensure No Device Files are Unlabeled by SELinux + + ocil:ssg-selinux_all_devicefiles_labeled_action:testaction:1 + + + + Ensure No Daemons are Unconfined by SELinux + + ocil:ssg-selinux_confinement_of_daemons_action:testaction:1 + + + + Ensure SELinux is Not Disabled + + ocil:ssg-selinux_not_disabled_action:testaction:1 + + + + Configure SELinux Policy + + ocil:ssg-selinux_policytype_action:testaction:1 + + + + Ensure SELinux State is Enforcing + + ocil:ssg-selinux_state_action:testaction:1 + + + + Disable At Service (atd) + + ocil:ssg-service_atd_disabled_action:testaction:1 + + + + Enable auditd Service + + ocil:ssg-service_auditd_enabled_action:testaction:1 + + + + Disable the Automounter + + ocil:ssg-service_autofs_disabled_action:testaction:1 + + + + Disable Avahi Server Software + + ocil:ssg-service_avahi-daemon_disabled_action:testaction:1 + + + + The Chronyd service is enabled + + ocil:ssg-service_chronyd_enabled_action:testaction:1 + + + + Enable cron Service + + ocil:ssg-service_crond_enabled_action:testaction:1 + + + + Disable debug-shell SystemD Service + + ocil:ssg-service_debug-shell_disabled_action:testaction:1 + + + + Enable the File Access Policy Service + + ocil:ssg-service_fapolicyd_enabled_action:testaction:1 + + + + Verify firewalld Enabled + + ocil:ssg-service_firewalld_enabled_action:testaction:1 + + + + Verify iptables Enabled + + ocil:ssg-service_iptables_enabled_action:testaction:1 + + + + Disable KDump Kernel Crash Analyzer (kdump) + + ocil:ssg-service_kdump_disabled_action:testaction:1 + + + + Verify nftables Service is Disabled + + ocil:ssg-service_nftables_disabled_action:testaction:1 + + + + Disable Odd Job Daemon (oddjobd) + + ocil:ssg-service_oddjobd_disabled_action:testaction:1 + + + + Enable the pcscd Service + + ocil:ssg-service_pcscd_enabled_action:testaction:1 + + + + Enable Postfix Service + + ocil:ssg-service_postfix_enabled_action:testaction:1 + + + + Disable Network Router Discovery Daemon (rdisc) + + ocil:ssg-service_rdisc_disabled_action:testaction:1 + + + + Disable rlogin Service + + ocil:ssg-service_rlogin_disabled_action:testaction:1 + + + + Enable the Hardware RNG Entropy Gatherer Service + + ocil:ssg-service_rngd_enabled_action:testaction:1 + + + + Ensure rsyncd service is disabled + + ocil:ssg-service_rsyncd_disabled_action:testaction:1 + + + + Enable rsyslog Service + + ocil:ssg-service_rsyslog_enabled_action:testaction:1 + + + + Disable snmpd Service + + ocil:ssg-service_snmpd_disabled_action:testaction:1 + + + + Disable Squid + + ocil:ssg-service_squid_disabled_action:testaction:1 + + + + Disable SSH Server If Possible + + ocil:ssg-service_sshd_disabled_action:testaction:1 + + + + Enable the OpenSSH Service + + ocil:ssg-service_sshd_enabled_action:testaction:1 + + + + Enable the SSSD Service + + ocil:ssg-service_sssd_enabled_action:testaction:1 + + + + Enable syslog-ng Service + + ocil:ssg-service_syslogng_enabled_action:testaction:1 + + + + Disable acquiring, saving, and processing core dumps + + ocil:ssg-service_systemd-coredump_disabled_action:testaction:1 + + + + Enable systemd-journald Service + + ocil:ssg-service_systemd-journald_enabled_action:testaction:1 + + + + Disable telnet Service + + ocil:ssg-service_telnet_disabled_action:testaction:1 + + + + Verify ufw Enabled + + ocil:ssg-service_ufw_enabled_action:testaction:1 + + + + Enable the USBGuard Service + + ocil:ssg-service_usbguard_enabled_action:testaction:1 + + + + Set Default firewalld Zone for Incoming Packets + + ocil:ssg-set_firewalld_default_zone_action:testaction:1 + + + + Set Default ip6tables Policy for Incoming Packets + + ocil:ssg-set_ip6tables_default_rule_action:testaction:1 + + + + Set Default iptables Policy for Incoming Packets + + ocil:ssg-set_iptables_default_rule_action:testaction:1 + + + + Set Default iptables Policy for Forwarded Packets + + ocil:ssg-set_iptables_default_rule_forward_action:testaction:1 + + + + Set Password Hashing Algorithm in /etc/libuser.conf + + ocil:ssg-set_password_hashing_algorithm_libuserconf_action:testaction:1 + + + + Set Password Hashing Algorithm in /etc/login.defs + + ocil:ssg-set_password_hashing_algorithm_logindefs_action:testaction:1 + + + + Set PAM''s Password Hashing Algorithm - password-auth + + ocil:ssg-set_password_hashing_algorithm_passwordauth_action:testaction:1 + + + + Set PAM''s Password Hashing Algorithm + + ocil:ssg-set_password_hashing_algorithm_systemauth_action:testaction:1 + + + + Set Password Hashing Rounds in /etc/login.defs + + ocil:ssg-set_password_hashing_min_rounds_logindefs_action:testaction:1 + + + + Configure SNMP Service to Use Only SNMPv3 or Newer + + ocil:ssg-snmpd_use_newer_protocol_action:testaction:1 + + + + Configure session renegotiation for SSH client + + ocil:ssg-ssh_client_rekey_limit_action:testaction:1 + + + + Verify the SSH Private Key Files Have a Passcode + + ocil:ssg-ssh_keys_passphrase_protected_action:testaction:1 + + + + Allow Only SSH Protocol 2 + + ocil:ssg-sshd_allow_only_protocol2_action:testaction:1 + + + + Disable Compression Or Set Compression to delayed + + ocil:ssg-sshd_disable_compression_action:testaction:1 + + + + Disable SSH Access via Empty Passwords + + ocil:ssg-sshd_disable_empty_passwords_action:testaction:1 + + + + Disable GSSAPI Authentication + + ocil:ssg-sshd_disable_gssapi_auth_action:testaction:1 + + + + Disable Kerberos Authentication + + ocil:ssg-sshd_disable_kerb_auth_action:testaction:1 + + + + Disable PubkeyAuthentication Authentication + + ocil:ssg-sshd_disable_pubkey_auth_action:testaction:1 + + + + Disable SSH Support for .rhosts Files + + ocil:ssg-sshd_disable_rhosts_action:testaction:1 + + + + Disable SSH Support for Rhosts RSA Authentication + + ocil:ssg-sshd_disable_rhosts_rsa_action:testaction:1 + + + + Disable SSH Root Login + + ocil:ssg-sshd_disable_root_login_action:testaction:1 + + + + Disable SSH root Login with a Password (Insecure) + + ocil:ssg-sshd_disable_root_password_login_action:testaction:1 + + + + Disable SSH TCP Forwarding + + ocil:ssg-sshd_disable_tcp_forwarding_action:testaction:1 + + + + Disable SSH Support for User Known Hosts + + ocil:ssg-sshd_disable_user_known_hosts_action:testaction:1 + + + + Disable X11 Forwarding + + ocil:ssg-sshd_disable_x11_forwarding_action:testaction:1 + + + + Do Not Allow SSH Environment Options + + ocil:ssg-sshd_do_not_permit_user_env_action:testaction:1 + + + + Enable GSSAPI Authentication + + ocil:ssg-sshd_enable_gssapi_auth_action:testaction:1 + + + + Enable PAM + + ocil:ssg-sshd_enable_pam_action:testaction:1 + + + + Enable Public Key Authentication + + ocil:ssg-sshd_enable_pubkey_auth_action:testaction:1 + + + + Enable Use of Strict Mode Checking + + ocil:ssg-sshd_enable_strictmodes_action:testaction:1 + + + + Enable SSH Warning Banner + + ocil:ssg-sshd_enable_warning_banner_action:testaction:1 + + + + Enable SSH Warning Banner + + ocil:ssg-sshd_enable_warning_banner_net_action:testaction:1 + + + + Enable Encrypted X11 Forwarding + + ocil:ssg-sshd_enable_x11_forwarding_action:testaction:1 + + + + Limit Users' SSH Access + + ocil:ssg-sshd_limit_user_access_action:testaction:1 + + + + Enable SSH Print Last Log + + ocil:ssg-sshd_print_last_log_action:testaction:1 + + + + Force frequent session key renegotiation + + ocil:ssg-sshd_rekey_limit_action:testaction:1 + + + + Set SSH Client Alive Interval + + ocil:ssg-sshd_set_idle_timeout_action:testaction:1 + + + + Set SSH Client Alive Count Max + + ocil:ssg-sshd_set_keepalive_action:testaction:1 + + + + Set SSH Client Alive Count Max to zero + + ocil:ssg-sshd_set_keepalive_0_action:testaction:1 + + + + Ensure SSH LoginGraceTime is configured + + ocil:ssg-sshd_set_login_grace_time_action:testaction:1 + + + + Set LogLevel to INFO + + ocil:ssg-sshd_set_loglevel_info_action:testaction:1 + + + + Set SSH Daemon LogLevel to VERBOSE + + ocil:ssg-sshd_set_loglevel_verbose_action:testaction:1 + + + + Set SSH authentication attempt limit + + ocil:ssg-sshd_set_max_auth_tries_action:testaction:1 + + + + Set SSH MaxSessions limit + + ocil:ssg-sshd_set_max_sessions_action:testaction:1 + + + + Ensure SSH MaxStartups is configured + + ocil:ssg-sshd_set_maxstartups_action:testaction:1 + + + + Distribute the SSH Server configuration to multiple files in a config directory. + + ocil:ssg-sshd_use_directory_configuration_action:testaction:1 + + + + Enable Use of Privilege Separation + + ocil:ssg-sshd_use_priv_separation_action:testaction:1 + + + + Prevent remote hosts from connecting to the proxy display + + ocil:ssg-sshd_x11_use_localhost_action:testaction:1 + + + + Certificate status checking in SSSD + + ocil:ssg-sssd_certificate_verification_action:testaction:1 + + + + Enable Certmap in SSSD + + ocil:ssg-sssd_enable_certmap_action:testaction:1 + + + + Configure PAM in SSSD Services + + ocil:ssg-sssd_enable_pam_services_action:testaction:1 + + + + Enable Smartcards in SSSD + + ocil:ssg-sssd_enable_smartcards_action:testaction:1 + + + + SSSD Has a Correct Trust Anchor + + ocil:ssg-sssd_has_trust_anchor_action:testaction:1 + + + + Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server + + ocil:ssg-sssd_ldap_configure_tls_reqcert_action:testaction:1 + + + + Configure SSSD LDAP Backend to Use TLS For All Transactions + + ocil:ssg-sssd_ldap_start_tls_action:testaction:1 + + + + Configure SSSD to Expire Offline Credentials + + ocil:ssg-sssd_offline_cred_expiration_action:testaction:1 + + + + Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC + + ocil:ssg-sudo_add_noexec_action:testaction:1 + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty + + ocil:ssg-sudo_add_requiretty_action:testaction:1 + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty + + ocil:ssg-sudo_add_use_pty_action:testaction:1 + + + + Ensure Sudo Logfile Exists - sudo logfile + + ocil:ssg-sudo_custom_logfile_action:testaction:1 + + + + Ensure a dedicated group owns sudo + + ocil:ssg-sudo_dedicated_group_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate + + ocil:ssg-sudo_remove_no_authenticate_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD + + ocil:ssg-sudo_remove_nopasswd_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo + + ocil:ssg-sudo_require_authentication_action:testaction:1 + + + + Require Re-Authentication When Using the sudo Command + + ocil:ssg-sudo_require_reauthentication_action:testaction:1 + + + + The operating system must restrict privilege elevation to authorized personnel + + ocil:ssg-sudo_restrict_privilege_elevation_to_authorized_action:testaction:1 + + + + Only the VDSM User Can Use sudo NOPASSWD + + ocil:ssg-sudo_vdsm_nopasswd_action:testaction:1 + + + + Explicit arguments in sudo specifications + + ocil:ssg-sudoers_explicit_command_args_action:testaction:1 + + + + Don't define allowed commands in sudoers by means of exclusion + + ocil:ssg-sudoers_no_command_negation_action:testaction:1 + + + + Don't target root user in the sudoers file + + ocil:ssg-sudoers_no_root_target_action:testaction:1 + + + + Ensure invoking users password for privilege escalation when using sudo + + ocil:ssg-sudoers_validate_passwd_action:testaction:1 + + + + Set kernel parameter 'crypto.fips_enabled' to 1 + + ocil:ssg-sysctl_crypto_fips_enabled_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + + ocil:ssg-sysctl_fs_protected_fifos_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + + ocil:ssg-sysctl_fs_protected_hardlinks_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Regular files + + ocil:ssg-sysctl_fs_protected_regular_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + + ocil:ssg-sysctl_fs_protected_symlinks_action:testaction:1 + + + + Disable Core Dumps for SUID programs + + ocil:ssg-sysctl_fs_suid_dumpable_action:testaction:1 + + + + Disable storing core dumps + + ocil:ssg-sysctl_kernel_core_pattern_action:testaction:1 + + + + Disable storing core dumps + + ocil:ssg-sysctl_kernel_core_pattern_empty_string_action:testaction:1 + + + + Configure file name of core dumps + + ocil:ssg-sysctl_kernel_core_uses_pid_action:testaction:1 + + + + Restrict Access to Kernel Message Buffer + + ocil:ssg-sysctl_kernel_dmesg_restrict_action:testaction:1 + + + + Enable ExecShield via sysctl + + ocil:ssg-sysctl_kernel_exec_shield_action:testaction:1 + + + + Disable Kernel Image Loading + + ocil:ssg-sysctl_kernel_kexec_load_disabled_action:testaction:1 + + + + Restrict Exposed Kernel Pointer Addresses Access + + ocil:ssg-sysctl_kernel_kptr_restrict_action:testaction:1 + + + + Disable loading and unloading of kernel modules + + ocil:ssg-sysctl_kernel_modules_disabled_action:testaction:1 + + + + Kernel panic on oops + + ocil:ssg-sysctl_kernel_panic_on_oops_action:testaction:1 + + + + Limit CPU consumption of the Perf system + + ocil:ssg-sysctl_kernel_perf_cpu_time_max_percent_action:testaction:1 + + + + Limit sampling frequency of the Perf system + + ocil:ssg-sysctl_kernel_perf_event_max_sample_rate_action:testaction:1 + + + + Disallow kernel profiling by unprivileged users + + ocil:ssg-sysctl_kernel_perf_event_paranoid_action:testaction:1 + + + + Configure maximum number of process identifiers + + ocil:ssg-sysctl_kernel_pid_max_action:testaction:1 + + + + Enable Randomized Layout of Virtual Address Space + + ocil:ssg-sysctl_kernel_randomize_va_space_action:testaction:1 + + + + Disallow magic SysRq key + + ocil:ssg-sysctl_kernel_sysrq_action:testaction:1 + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_action:testaction:1 + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_accept_default_action:testaction:1 + + + + Restrict usage of ptrace to descendant processes + + ocil:ssg-sysctl_kernel_yama_ptrace_scope_action:testaction:1 + + + + Harden the operation of the BPF just-in-time compiler + + ocil:ssg-sysctl_net_core_bpf_jit_harden_action:testaction:1 + + + + Disable Accepting Packets Routed Between Local Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_local_action:testaction:1 + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_source_route_action:testaction:1 + + + + Configure ARP filtering for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_arp_filter_action:testaction:1 + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_arp_ignore_action:testaction:1 + + + + Drop Gratuitous ARP frames on All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_drop_gratuitous_arp_action:testaction:1 + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_forwarding_action:testaction:1 + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_log_martians_action:testaction:1 + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_route_localnet_action:testaction:1 + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_rp_filter_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_secure_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_send_redirects_action:testaction:1 + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_shared_media_action:testaction:1 + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_default_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_accept_source_route_action:testaction:1 + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_log_martians_action:testaction:1 + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_rp_filter_action:testaction:1 + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + + ocil:ssg-sysctl_net_ipv4_conf_default_secure_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_send_redirects_action:testaction:1 + + + + Configure Sending and Accepting Shared Media Redirects by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_shared_media_action:testaction:1 + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts_action:testaction:1 + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses_action:testaction:1 + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_ip_forward_action:testaction:1 + + + + Set Kernel Parameter to Increase Local Port Range + + ocil:ssg-sysctl_net_ipv4_ip_local_port_range_action:testaction:1 + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_tcp_rfc1337_action:testaction:1 + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + + ocil:ssg-sysctl_net_ipv4_tcp_syncookies_action:testaction:1 + + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_action:testaction:1 + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_defrtr_action:testaction:1 + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_pinfo_action:testaction:1 + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_action:testaction:1 + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_source_route_action:testaction:1 + + + + Configure Auto Configuration on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_autoconf_action:testaction:1 + + + + Disable IPv6 Addressing on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_disable_ipv6_action:testaction:1 + + + + Disable Kernel Parameter for IPv6 Forwarding + + ocil:ssg-sysctl_net_ipv6_conf_all_forwarding_action:testaction:1 + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_max_addresses_action:testaction:1 + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_router_solicitations_action:testaction:1 + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_action:testaction:1 + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_defrtr_action:testaction:1 + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_pinfo_action:testaction:1 + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_action:testaction:1 + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_source_route_action:testaction:1 + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_autoconf_action:testaction:1 + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_disable_ipv6_action:testaction:1 + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_max_addresses_action:testaction:1 + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_router_solicitations_action:testaction:1 + + + + Disable the use of user namespaces + + ocil:ssg-sysctl_user_max_user_namespaces_action:testaction:1 + + + + Prevent applications from mapping low portion of virtual memory + + ocil:ssg-sysctl_vm_mmap_min_addr_action:testaction:1 + + + + Ensure tmp.mount Unit Is Enabled + + ocil:ssg-systemd_tmp_mount_enabled_action:testaction:1 + + + + Ensure tftp systemd Service Uses Secure Mode + + ocil:ssg-tftp_uses_secure_mode_systemd_action:testaction:1 + + + + Enable dnf-automatic Timer + + ocil:ssg-timer_dnf-automatic_enabled_action:testaction:1 + + + + Enable logrotate Timer + + ocil:ssg-timer_logrotate_enabled_action:testaction:1 + + + + Authorize Human Interface Devices and USB hubs in USBGuard daemon + + ocil:ssg-usbguard_allow_hid_and_hub_action:testaction:1 + + + + Generate USBGuard Policy + + ocil:ssg-usbguard_generate_policy_action:testaction:1 + + + + Use Kerberos Security on All Exports + + ocil:ssg-use_kerberos_security_all_exports_action:testaction:1 + + + + Enforce usage of pam_wheel for su authentication + + ocil:ssg-use_pam_wheel_for_su_action:testaction:1 + + + + Enforce Usage of pam_wheel with Group Parameter for su Authentication + + ocil:ssg-use_pam_wheel_group_for_su_action:testaction:1 + + + + Deactivate Wireless Network Interfaces + + ocil:ssg-wireless_disable_interfaces_action:testaction:1 + + + + Disable graphical user interface + + ocil:ssg-xwindows_remove_packages_action:testaction:1 + + + + Disable Graphical Environment Startup By Setting Default Target + + ocil:ssg-xwindows_runlevel_target_action:testaction:1 + + - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - + PASS @@ -250932,7 +270016,7 @@ fi FAIL - + PASS @@ -250940,7 +270024,7 @@ fi FAIL - + PASS @@ -250948,2111 +270032,7 @@ fi FAIL - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - + PASS @@ -253068,7 +270048,7 @@ fi FAIL - + PASS @@ -253076,7 +270056,7 @@ fi FAIL - + PASS @@ -253084,7 +270064,7 @@ fi FAIL - + PASS @@ -253092,7 +270072,7 @@ fi FAIL - + PASS @@ -253100,7 +270080,7 @@ fi FAIL - + PASS @@ -253108,7 +270088,7 @@ fi FAIL - + PASS @@ -253116,127 +270096,7 @@ fi FAIL - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - + PASS @@ -253252,7 +270112,7 @@ fi FAIL - + PASS @@ -253260,7 +270120,7 @@ fi FAIL - + PASS @@ -253268,7 +270128,7 @@ fi FAIL - + PASS @@ -253276,7 +270136,7 @@ fi FAIL - + PASS @@ -253284,7 +270144,7 @@ fi FAIL - + PASS @@ -253292,7 +270152,143 @@ fi FAIL - + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + PASS @@ -253316,7 +270312,7 @@ fi FAIL - + PASS @@ -253324,7 +270320,7 @@ fi FAIL - + PASS @@ -253332,7 +270328,7 @@ fi FAIL - + PASS @@ -253340,7 +270336,7 @@ fi FAIL - + PASS @@ -253348,7 +270344,7 @@ fi FAIL - + PASS @@ -253356,7 +270352,7 @@ fi FAIL - + PASS @@ -253364,7 +270360,7 @@ fi FAIL - + PASS @@ -253372,7 +270368,983 @@ fi FAIL - + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + PASS @@ -253388,6 +271360,1030 @@ fi FAIL + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + PASS @@ -253396,6 +272392,782 @@ fi FAIL + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + PASS @@ -253404,317 +273176,4311 @@ fi FAIL + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + - - Verify that yum verifies the signature of packages from a repository prior to install with the following command: + + To verify the inactive setting, run the following command: +$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth +The output should indicate the inactive configuration option is set +to an appropriate integer between 1 and +; and should appear +before the pam_unix.so module as shown in the example below: +$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth +auth required pam_lastlog.so inactive= +auth sufficient pam_unix.so + Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? + + + + To verify the inactive setting, run the following command: +$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth +The output should indicate the inactive configuration option is set +to an appropriate integer between 1 and +; and should appear +before the pam_unix.so module as shown in the example below: +$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth +auth required pam_lastlog.so inactive= +auth sufficient pam_unix.so + Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? + + + + To verify the INACTIVE setting, run the following command: +$ grep "INACTIVE" /etc/default/useradd +The output should indicate the INACTIVE configuration option is set +to an appropriate integer as shown in the example below: +$ grep "INACTIVE" /etc/default/useradd +INACTIVE= + Is it the case that the value of INACTIVE is greater than the expected value or is -1? + + + + Verify the pam_faillock.so module is present in the "/etc/pam.d/password-auth" file: -$ grep gpgcheck /etc/yum.conf +$ sudo grep pam_faillock.so /etc/pam.d/password-auth -gpgcheck=1 +auth required pam_faillock.so preauth +auth required pam_faillock.so authfail +account required pam_faillock.so + Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/password-auth" file with the "preauth" line listed before pam_unix.so? + + + + Verify the pam_faillock.so module is present in the "/etc/pam.d/system-auth" file: -If "gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. - Is it the case that there is no process to validate certificates that is approved by the organization? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "unix_chkpwd" command with the following command: +$ sudo grep pam_faillock.so /etc/pam.d/system-auth -$ sudo auditctl -l | grep unix_chkpwd +auth required pam_faillock.so preauth +auth required pam_faillock.so authfail +account required pam_faillock.so + Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/system-auth" file with the "preauth" line listed before pam_unix.so? + + + + If the system does not have SELinux enabled and enforcing a targeted policy, or if the +pam_faillock.so module is not configured for use, this requirement is not applicable. --a always,exit -F path=/usr/bin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_chkpwd - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv4.conf.default.log_martians kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.log_martians -1. +Verify the location of the non-default tally directory for the pam_faillock.so module with +the following command: - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/nftables, -run the command: -$ ls -l /etc/nftables -If properly configured, the output should indicate the following permissions: -0700 - Is it the case that /etc/nftables does not have unix mode 0700? - - - - To verify all files and directories contained in interactive user home -directory, excluding local initialization files, have a mode of 0750, -run the following command: -$ sudo ls -lLR /home/USER - Is it the case that home directory files or folders have incorrect permissions? - - - - To check the ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/grub.cfg does not have an owner of root? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes rng_core.default_quality=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*rng_core.default_quality=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*rng_core.default_quality=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'rng_core.default_quality=' -The command should not return any output. - Is it the case that trust on hardware random number generator is not configured appropriately? - - - - Verify Oracle Linux 9 defines default permissions for all authenticated users in such a way that the user can only read and modify their own files with the following command: +$ sudo grep -w dir /etc/security/faillock.conf -# grep -i umask /etc/login.defs +dir = /var/log/faillock -UMASK - Is it the case that the value for the "UMASK" parameter is not "<sub idref="var_accounts_user_umask" />", or the "UMASK" parameter is missing or is commented out? - - - - Run the following command to determine if the talk-server package is installed: -$ rpm -q talk-server - Is it the case that the package is installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_VSYSCALL_XONLY /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - -If the system is configured to prevent the loading of the rds kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. +Check the security context type of the non-default tally directory with the following command: -These lines can also instruct the module loading system to ignore the rds kernel module via blacklist keyword. +$ sudo ls -Zd /var/log/faillock -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r rds /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? +unconfined_u:object_r:faillog_t:s0 /var/log/faillock + Is it the case that the security context type of the non-default tally directory is not "faillog_t"? - - Run the following command to ensure postfix routes mail to this system: -$ grep relayhost /etc/postfix/main.cf -If properly configured, the output should show only . - Is it the case that it is not? - - - - To check the group ownership of /etc/cron.monthly, -run the command: -$ ls -lL /etc/cron.monthly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.monthly does not have a group owner of root? - - - - Verify the TFTP daemon is configured to operate in secure mode. + + Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: -Check if a TFTP server is installed with the following command: +$ sudo grep audit /etc/security/faillock.conf -$ sudo dnf list --installed tftp-server +audit + Is it the case that the "audit" option is not set, is missing or commented out? + + + + Verify the "/etc/security/faillock.conf" file is configured use a non-default faillock directory to ensure contents persist after reboot: -tftp-server.x86_64 5.2-35.el9.x86_64 +$ sudo grep 'dir =' /etc/security/faillock.conf +dir = /var/log/faillock + Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? + + + + Verify that temporary accounts have been provisioned with an expiration date +of 72 hours. For every temporary account, run the following command to +obtain its account aging and expiration information: +$ sudo chage -l temporary_account_name +Verify each of these accounts has an expiration date set within 72 hours or +as documented. + Is it the case that any temporary accounts have no expiration date set or do not expire within 72 hours? + + + + Verify that Oracle Linux 9 contains no duplicate User IDs (UIDs) for interactive users. -If a TFTP server is not installed, this is Not Applicable. +Check that the operating system contains no duplicate UIDs for interactive users with the following command: +$ sudo awk -F ":" 'list[$3]++{print $1, $3}' /etc/passwd + Is it the case that output is produced and the accounts listed are interactive user accounts? + + + + To verify all accounts have unique names, run the following command: +$ sudo getent passwd | awk -F: '{ print $1}' | uniq -d +No output should be returned. + Is it the case that a line is returned? + + + + Verify that the system is integrated with a centralized authentication mechanism +such as as Active Directory, Kerberos, Directory Server, etc. that has +automated account mechanisms in place. + Is it the case that the system is not using a centralized authentication mechanism, or it is not automated? + + + + To verify that there are no unauthorized local user accounts, run the following command: +$ less /etc/passwd +Inspect the results, and if unauthorized local user accounts exist, remove them by running +the following command: +$ sudo userdel unauthorized_user + Is it the case that there are unauthorized local user accounts on the system? + + + + Verify all local interactive users on Oracle Linux 9 are assigned a home +directory upon creation with the following command: +$ grep -i create_home /etc/login.defs +CREATE_HOME yes + Is it the case that the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out? + + + + Verify Oracle Linux 9 enforces a delay of at least seconds between console logon prompts following a failed logon attempt with the following command: -If a TFTP server is installed, check for the server arguments with the following command: - -$ systemctl cat tftp | grep ExecStart= -ExecStart=/usr/sbin/in.tftpd -s - Is it the case that 'the "ExecStart" line does not have a "-s" option, and a subdirectory is not assigned'? - - - - To verify /etc/system-fips exists, run the following command: -ls -l /etc/system-fips -The output should be similar to the following: --rw-r--r--. 1 root root 36 Nov 26 11:31 /etc/system-fips - Is it the case that /etc/system-fips does not exist? - - - - To determine if the system is configured to audit calls to the -lchown system call, run the following command: -$ sudo grep "lchown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Run the following command to determine if the squid package is installed: -$ rpm -q squid - Is it the case that the package is installed? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes vsyscall=none, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*vsyscall=none.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*vsyscall=none.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'vsyscall=none' -The command should not return any output. - Is it the case that vsyscalls are enabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_SHA512 /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to prevent the usage of the ipv6 on -network interfaces, it will contain a line of the form: -net.ipv6.conf.all.disable_ipv6 = 1 -Such lines may be inside any file in the /etc/sysctl.d directory. -This permits insertion of the IPv6 kernel module (which other parts of the -system expect to be present), but otherwise keeps all network interfaces -from using IPv6. Run the following command to search for such lines in all -files in /etc/sysctl.d: -$ grep -r ipv6 /etc/sysctl.d - Is it the case that the ipv6 support is disabled on all network interfaces? - - - - If the system is not using TLS, set the ldap_id_use_start_tls option -in /etc/sssd/sssd.conf to true. - Is it the case that the 'ldap_id_use_start_tls' option is not set to 'true'? - - - - To verify that binaries cannot be directly executed from removable media, run the following command: -$ grep -v noexec /etc/fstab -The resulting output will show partitions which do not have the noexec flag. Verify all partitions -in the output are not removable media. - Is it the case that removable media partitions are present? - - - - To check the group ownership of /etc/sysctl.d, -run the command: -$ ls -lL /etc/sysctl.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sysctl.d does not have a group owner of root? - - - - To check the group ownership of /etc/sudoers, -run the command: -$ ls -lL /etc/sudoers -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sudoers does not have a group owner of root? - - - - The runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - Verify that the libuser is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. - - -Check the hashing algorithm that is being used to hash passwords with the following command: - -$ sudo grep -i crypt_style /etc/libuser.conf - -crypt_style = - Is it the case that crypt_style is not set to sha512? - - - - The runtime status of the fs.protected_symlinks kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_symlinks -1. - - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/ipsec.d, -run the command: -$ ls -l /etc/ipsec.d -If properly configured, the output should indicate the following permissions: -0700 - Is it the case that /etc/ipsec.d does not have unix mode 0700? - - - - To obtain a listing of all users, their UIDs, and their shells, run the command: -$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd -Identify the system accounts from this listing. These will primarily be the accounts with UID -numbers less than 1000, other than root. - Is it the case that any system account other than root has a login shell? - - - - Verify the nodev option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . nodev . . . - - Is it the case that the "/var/log" file system does not have the "nodev" option set? - - - - Verify that cron is logging to rsyslog, -run the following command: -grep -rni "cron\.\*" /etc/rsyslog.* -cron.* /var/log/cron -or -cron.* action(type="omfile" file="/var/log/cron") - Is it the case that cron is not logging to rsyslog? - - - - Run the following command to determine if the dnf-automatic package is installed: $ rpm -q dnf-automatic - Is it the case that the package is not installed? +$ sudo grep -i "FAIL_DELAY" /etc/login.defs +FAIL_DELAY + Is it the case that the value of "FAIL_DELAY" is not set to "<sub idref="var_accounts_fail_delay" />" or greater, or the line is commented out? @@ -253731,158 +277497,92 @@ operational requirement for all domains that have the "maxlogins" item assigned'? - - Verify Oracle Linux 9 removes all software components after updated versions have been installed. + + Verify that Oracle Linux 9 enforces a -day maximum password lifetime for new user accounts by running the following command: +$ grep -i pass_max_days /etc/login.defs -$ grep clean_requirements_on_remove /etc/yum.conf -clean_requirements_on_remove=1 - Is it the case that '"clean_requirements_on_remove" is not set to "1"'? +PASS_MAX_DAYS + Is it the case that the "PASS_MAX_DAYS" parameter value is greater than "<sub idref="var_accounts_maximum_age_login_defs" />", or commented out? - - Run the following command to determine if the dhcp-server package is installed: -$ rpm -q dhcp-server - Is it the case that the package is installed? - - - - To check the permissions of /boot/System.map*, -run the command: -$ ls -l /boot/System.map* -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /boot/System.map* does not have unix mode -rw-------? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECCOMP_FILTER /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if authentication is required for emergency mode, run the following command: -$ grep sulogin /usr/lib/systemd/system/emergency.service -The output should be similar to the following, and the line must begin with -ExecStart and /usr/lib/systemd/systemd-sulogin-shell. - ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + + Verify Oracle Linux 9 enforces 24 hours/one day as the minimum password lifetime for new user accounts. -Then, check if the emergency target requires the emergency service: -Run the following command: -$ sudo grep Requires /usr/lib/systemd/system/emergency.target -The output should be the following: -Requires=emergency.service +Check for the value of "PASS_MIN_DAYS" in "/etc/login.defs" with the following command: -Then, check if there is no custom emergency target configured in systemd configuration. -Run the following command: -$ sudo grep -r emergency.target /etc/systemd/system/ -The output should be empty. +$ grep -i pass_min_days /etc/login.defs -Then, check if there is no custom emergency service configured in systemd configuration. -Run the following command: -$ sudo grep -r emergency.service /etc/systemd/system/ -The output should be empty. - Is it the case that the output is different? +PASS_MIN_DAYS + Is it the case that the "PASS_MIN_DAYS" parameter value is not "<sub idref="var_accounts_minimum_age_login_defs" />" or greater, or is commented out? - - To ensure ClientAliveInterval is set correctly, run the following command: -$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config -If properly configured, the output should be: -ClientAliveCountMax -For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when -the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout -functionality completely. -If the option is set to a number greater than 0, then the session will be disconnected after -ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message. - Is it the case that it is commented out or not configured properly? + + Verify that only the "root" account has a UID "0" assignment with the +following command: +$ awk -F: '$3 == 0 {print $1}' /etc/passwd +root + Is it the case that any accounts other than "root" have a UID of "0"? - - To verify the nodev option is configured for non-root local partitions, run the following command: -$ sudo mount | grep '^/dev\S* on /\S' | grep --invert-match 'nodev' -The output shows local non-root partitions mounted without the nodev option, and there should be no output at all. - - Is it the case that some mounts appear among output lines? + + To check that no password hashes are stored in +/etc/passwd, run the following command: +awk '!/\S:x|\*/ {print}' /etc/passwd +If it produces any output, then a password hash is +stored in /etc/passwd. + Is it the case that any stored hashes are found in /etc/passwd? - - Verify that local initialization files do not execute world-writable programs with the following command: + + Verify that the interactive user account passwords are using a strong +password hash with the following command: -Note: The example will be for a system that is configured to create user home directories in the "/home" directory. +$ sudo cut -d: -f2 /etc/shadow -$ sudo find /home -perm -002 -type f -name ".[^.]*" -exec ls -ld {} \; - Is it the case that any local initialization files are found to reference world-writable files? +$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/ + +Password hashes ! or * indicate inactive accounts not +available for logon and are not evaluated. + Is it the case that any interactive user password hash does not begin with "$6"? - - Verify that interactive users on the system have a home directory assigned with the following command: - -$ sudo awk -F: '($3>=1000)&&($7 !~ /nologin/){print $1, $3, $6}' /etc/passwd - -Inspect the output and verify that all interactive users (normally users with a UID greater than 1000) have a home directory defined. - Is it the case that users home directory is not defined? + + Verify that the interactive user account passwords last change time is not in the future +The following command should return no output +$ sudo expiration=$(cat /etc/shadow|awk -F ':' '{print $3}'); +for edate in ${expiration[@]}; do if [[ $edate > $(( $(date +%s)/86400 )) ]]; +then echo "Expiry date in future"; +fi; done + Is it the case that any interactive user password that has last change time in the future? - - The runtime status of the net.ipv6.conf.all.accept_ra kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra -0. + + To check the minimum password length, run the command: +$ grep PASS_MIN_LEN /etc/login.defs +The profile requirement is +. + Is it the case that it is not set to the required value? + + + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one numeric character be used. - Is it the case that the correct value is not returned? - - - - Verify the nodev option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . nodev . . . +Check the value for "dcredit" with the following command: - Is it the case that the "/tmp" file system does not have the "nodev" option set? - - - - The rsh package can be removed with the following command: $ sudo yum erase rsh - Is it the case that ? - - - - Verify the nosuid option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . nosuid . . . +$ sudo grep dcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - Is it the case that the "/var/tmp" file system does not have the "nosuid" option set? +/etc/security/pwquality.conf:dcredit = + Is it the case that the value of "dcredit" is a positive number or is commented out? - - For each private key stored on the system, use the following command: -$ sudo ssh-keygen -y -f /path/to/file -If the contents of the key are displayed, this is a finding. - Is it the case that no ssh private key is accessible without a passcode? - - - - Ensure that Oracle Linux 9 does not disable SELinux. + + Verify Oracle Linux 9 prevents the use of dictionary words for passwords with the following command: -Check if "SELinux" is active and in "enforcing" or "permissive" mode with the following command: +$ sudo grep dictcheck /etc/security/pwquality.conf /etc/pwquality.conf.d/*.conf -$ sudo getenforce -Enforcing --OR- -Permissive - Is it the case that SELinux is disabled? - - - - Run the following command to determine if the cronie package is installed: -$ rpm -q cronie - Is it the case that the package is installed? +/etc/security/pwquality.conf:dictcheck=1 + Is it the case that "dictcheck" does not have a value other than "0", or is commented out? @@ -253894,83 +277594,15 @@ difok = Is it the case that the value of "difok" is set to less than "<sub idref="var_password_pam_difok" />", or is commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECCOMP /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure that remote access requires credentials, run the following command: -$ gsettings get org.gnome.Vino authentication-methods -If properly configured, the output should be false. -To ensure that users cannot disable credentials for remote access, run the following: -$ grep authentication-methods /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/Vino/authentication-methods - Is it the case that wireless network notification is enabled and not disabled? - - - - To check the group ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/user.cfg does not have a group owner of root? - - - - Verify the system-wide shared library directories are owned by "root" with the following command: + + Verify that Oracle Linux 9 enforces password complexity rules for the root account. -$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -user root -type d -exec stat -c "%n %U" '{}' \; - Is it the case that any system-wide shared library directory is not owned by root? - - - - Verify the system-wide shared library files are group-owned by "root" with the following command: +Check if root user is required to use complex passwords with the following command: -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -group root -exec ls -l {} \; - Is it the case that any system wide shared library file is returned and is not group-owned by a required system account? - - - - To verify ExecShield is enabled on 64-bit Oracle Linux 9 systems, -run the following command: -$ dmesg | grep '[NX|DX]*protection' -The output should not contain 'disabled by kernel command line option'. -Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes noexec=off, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*noexec=off.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*noexec=off.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'noexec=off' -The command should not return any output. - Is it the case that ExecShield is not supported by the hardware, is not enabled, or has been disabled by the kernel configuration.? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd with the following command: +$ grep enforce_for_root /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf -$ sudo auditctl -l | grep -E '(/etc/shadow)' - --w /etc/shadow -p wa -k identity - Is it the case that command does not return a line, or the line is commented out? - - - - To verify all files and directories in a local interactive user's -home directory have a valid owner, run the following command: -$ sudo ls -lLR /home/USER - Is it the case that the user ownership is incorrect? +/etc/security/pwquality.conf:enforce_for_root + Is it the case that "enforce_for_root" is commented or missing? @@ -253984,299 +277616,22 @@ $ sudo grep lcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/ Is it the case that the value of "lcredit" is a positive number or is commented out? - - + + Verify the value of the "maxclassrepeat" option in "/etc/security/pwquality.conf" with the following command: -Run the following command to determine the current status of the -chronyd service: -$ sudo systemctl is-active chronyd -If the service is running, it should return the following: active - Is it the case that the chronyd process is not running? - - - - Run the following command to determine if the firewalld package is installed: $ rpm -q firewalld - Is it the case that the package is not installed? - - - - To check the permissions of /etc/sudoers.d, -run the command: -$ ls -l /etc/sudoers.d -If properly configured, the output should indicate the following permissions: -0750 - Is it the case that /etc/sudoers.d does not have unix mode 0750? - - - - To check the current idle time-out value, run the following command: -$ gsettings get org.gnome.desktop.session idle-delay -If properly configured, the output should be 'uint32 '. -To ensure that users cannot change the screensaver inactivity timeout setting, run the following: -$ grep idle-delay /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/session/idle-delay - Is it the case that idle-delay is set to 0 or a value greater than <sub idref="inactivity_timeout_value" />? - - - - To determine if the system is configured to audit account changes, -run the following command: -auditctl -l | grep -E '(/etc/passwd|/etc/shadow|/etc/group|/etc/gshadow|/etc/security/opasswd)' -If the system is configured to watch for account changes, lines should be returned for -each file specified (and with perm=wa for each). - Is it the case that the system is not configured to audit account changes? - - - - To check the permissions of /etc/ssh/sshd_config, -run the command: -$ ls -l /etc/ssh/sshd_config -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/ssh/sshd_config does not have unix mode -rw-------? - - - - root password is not set - Is it the case that Perform the following to determine if a password is set for the -root user: -<pre># grep -Eq '^root:\$[0-9]' /etc/shadow || echo "root is locked"</pre> -No results should be returned. -Otherwise, run the following command and follow the prompts to set a -password for the root user: -<pre># passwd root</pre>? - - - - To verify that USB Human Interface Devices and hubs will be authorized by the USBGuard daemon, -run the following command: -$ sudo grep allow /etc/usbguard/rules.conf -The output lines should include -allow with-interface match-all { 03:*:* 09:00:* } - Is it the case that USB devices of class 3 and 9:00 are not authorized? - - - - Verify that a separate file system/partition has been created for /tmp with the following command: +$ grep maxclassrepeat /etc/security/pwquality.conf -$ mountpoint /tmp +maxclassrepeat = + Is it the case that the value of "maxclassrepeat" is set to "0", more than "<sub idref="var_password_pam_maxclassrepeat" />" or is commented out? + + + + Verify the value of the "maxrepeat" option in "/etc/security/pwquality.conf" with the following command: - Is it the case that "/tmp is not a mountpoint" is returned? - - - - +$ grep maxrepeat /etc/security/pwquality.conf -Run the following command to determine the current status of the -sshd service: -$ sudo systemctl is-active sshd -If the service is running, it should return the following: active - Is it the case that sshd service is disabled? - - - - To check the permissions of /boot/grub2/grub.cfg, run the command: -$ sudo ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following -permissions: -rw------- - Is it the case that it does not? - - - - To determine how the SSH daemon's Banner option is set, run the following command: - -$ sudo grep -i Banner /etc/ssh/sshd_config - -If a line indicating /etc/issue.net is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - The runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.icmp_ignore_bogus_error_responses -1. - - Is it the case that the correct value is not returned? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules -The output has to be exactly as follows: -## Successful permission change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change - Is it the case that the file does not exist or the content differs? - - - - -If the system is configured to prevent the loading of the bluetooth kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the bluetooth kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r bluetooth /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Run the following command to determine if the libselinux package is installed: $ rpm -q libselinux - Is it the case that the package is not installed? - - - - To check the ownership of /etc/gshadow, -run the command: -$ ls -lL /etc/gshadow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/gshadow does not have an owner of root? - - - - Run the following command to determine if the net-snmp package is installed: -$ rpm -q net-snmp - Is it the case that the package is installed? - - - - The ftp package can be removed with the following command: $ sudo yum erase ftp - Is it the case that ? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "poweroff" command with the following command: - -$ sudo auditctl -l | grep poweroff - --a always,exit -F path=/poweroff -F perm=x -F auid>=1000 -F auid!=unset -k privileged-poweroff - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/gshadow-, -run the command: -$ ls -lL /etc/gshadow- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/gshadow- does not have a group owner of root? - - - - To check the ownership of /var/log/messages, -run the command: -$ ls -lL /var/log/messages -If properly configured, the output should indicate the following owner: -root - Is it the case that /var/log/messages does not have an owner of root? - - - - To determine if the system is configured to audit calls to the -umount2 system call, run the following command: -$ sudo grep "umount2" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - The following command will locate the mount points related to local devices: -$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) - -The following command will show files which do not belong to a valid group: -$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null - -Replace MOUNTPOINT by the mount points listed by the fist command. - -No files without a valid group should be located. - Is it the case that there is output? - - - - Verify the nosuid option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . nosuid . . . - - Is it the case that the "/dev/shm" file system does not have the "nosuid" option set? - - - - -To properly set the permissions of /etc/audit/, run the command: -$ sudo chmod 0640 /etc/audit/ - -To properly set the permissions of /etc/audit/rules.d/, run the command: -$ sudo chmod 0640 /etc/audit/rules.d/ - Is it the case that ? - - - - To check the permissions of /etc/audit/rules.d/*.rules, -run the command: -$ ls -l /etc/audit/rules.d/*.rules -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/audit/rules.d/*.rules does not have unix mode -rw-------? - - - - To check the group ownership of /usr/bin/sudo, -run the command: -$ ls -lL /usr/bin/sudo -If properly configured, the output should indicate the following group-owner: - - Is it the case that /usr/bin/sudo does not have a group owner of <sub idref="var_sudo_dedicated_group" />? - - - - Verify that a separate file system/partition has been created for /srv with the following command: - -$ mountpoint /srv - - Is it the case that "/srv is not a mountpoint" is returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RANDOMIZE_BASE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_NOTIFIERS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure the failed password attempt policy is configured correctly, run the following command: - -$ grep fail_interval /etc/security/faillock.conf -The output should show fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. - Is it the case that the "fail_interval" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_fail_interval" />" -or less (but not "0"), the line is commented out, or the line is missing? +maxrepeat = + Is it the case that the value of "maxrepeat" is set to more than "<sub idref="var_password_pam_maxrepeat" />" or is commented out? @@ -254288,1321 +277643,44 @@ minclass = Is it the case that the value of "minclass" is set to less than "<sub idref="var_password_pam_minclass" />" or is commented out? - - To determine if the system is configured to audit changes to its network configuration, -run the following command: -auditctl -l | grep -E '(/etc/issue|/etc/issue.net|/etc/hosts|/etc/sysconfig/network)' + + Verify that Oracle Linux 9 enforces a minimum -character password length with the following command: -If the system is configured to watch for network configuration changes, a line should be returned for -each file specified (and perm=wa should be indicated for each). - Is it the case that the system is not configured to audit changes of the network configuration? - - - - To ensure that users cannot change session idle and lock settings, run the following: -$ grep 'lock-delay' /etc/dconf/db/local.d/locks/* -If properly configured, the output should return: -/org/gnome/desktop/screensaver/lock-delay - Is it the case that GNOME3 session settings are not locked or configured properly? - - - - -Run the following command to determine if the authlogin_nsswitch_use_ldap SELinux boolean is disabled: -$ getsebool authlogin_nsswitch_use_ldap -If properly configured, the output should show the following: -authlogin_nsswitch_use_ldap --> off - Is it the case that authlogin_nsswitch_use_ldap is not disabled? - - - - In order to be sure that the databases are up-to-date, run the -dconf update -command as the administrator. - Is it the case that The system-wide dconf databases are up-to-date with regards to respective keyfiles? - - - - To determine if the system is configured to audit calls to the -fchmod system call, run the following command: -$ sudo grep "fchmod" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check that no password hashes are stored in -/etc/passwd, run the following command: -awk '!/\S:x|\*/ {print}' /etc/passwd -If it produces any output, then a password hash is -stored in /etc/passwd. - Is it the case that any stored hashes are found in /etc/passwd? - - - - To check which SSH protocol version is allowed, check version of openssh-server with following command: - -$ rpm -qi openssh-server | grep Version - -Versions equal to or higher than 7.4 only allow Protocol 2. -If version is lower than 7.4, run the following command to check configuration: -$ sudo grep Protocol /etc/ssh/sshd_config -If configured properly, output should be Protocol 2 - Is it the case that it is commented out or is not set correctly to Protocol 2? - - - - Verify that there are no wireless interfaces configured on the system -with the following command: - -Note: This requirement is Not Applicable for systems that do not have physical wireless network radios. - -$ nmcli device status -DEVICE TYPE STATE CONNECTION -virbr0 bridge connected virbr0 -wlp7s0 wifi connected wifiSSID -enp6s0 ethernet disconnected -- -p2p-dev-wlp7s0 wifi-p2p disconnected -- -lo loopback unmanaged -- -virbr0-nic tun unmanaged -- - Is it the case that a wireless interface is configured and has not been documented and approved by the Information System Security Officer (ISSO)? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-1-create-success.rules -The output has to be exactly as follows: -## Successful file creation (open with O_CREAT) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create - Is it the case that the file does not exist or the content differs? - - - - Run the following command to determine if the cryptsetup package is installed: $ rpm -q cryptsetup - Is it the case that the package is not installed? - - - - To ensure the system is configured to mask the Ctrl-Alt-Del sequence, Check -that the ctrl-alt-del.target is masked and not active with the following -command: -sudo systemctl status ctrl-alt-del.target -The output should indicate that the target is masked and not active. It -might resemble following output: -ctrl-alt-del.target -Loaded: masked (/dev/null; bad) -Active: inactive (dead) - Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed? - - - - Run the following command to determine if the opensc package is installed: $ rpm -q opensc - Is it the case that the package is not installed? - - - - To verify that there are no unauthorized local user accounts, run the following command: -$ less /etc/passwd -Inspect the results, and if unauthorized local user accounts exist, remove them by running -the following command: -$ sudo userdel unauthorized_user - Is it the case that there are unauthorized local user accounts on the system? - - - - To ensure root may not directly login to the system over physical consoles, -run the following command: -cat /etc/securetty -If any output is returned, this is a finding. - Is it the case that the /etc/securetty file is not empty? - - - - To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: - -$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - -To properly set the owner of /etc/audit/, run the command: -$ sudo chown root /etc/audit/ - -To properly set the owner of /etc/audit/rules.d/, run the command: -$ sudo chown root /etc/audit/rules.d/ - Is it the case that ? - - - - To determine if the system is configured to audit calls to the -init_module system call, run the following command: -$ sudo grep "init_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 set the days of warning before a password expires to - or more for users with a -password: - -$ sudo awk -F: '$6 || $6 == "" {print $1}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - To determine if the system is configured to audit calls to the -chown system call, run the following command: -$ sudo grep "chown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Run the following command to determine if the nfs-utils package is installed: -$ rpm -q nfs-utils - Is it the case that the package is installed? - - - - System commands are stored in the following directories: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -For each of these directories, run the following command to find directories not -owned by root: -$ sudo find -L $DIR ! -user root -type d - Is it the case that any of these directories are not owned by root? - - - - To check the ownership of /etc/group, -run the command: -$ ls -lL /etc/group -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/group does not have an owner of root? - - - - Run the following command to determine if the cyrus-imapd package is installed: -$ rpm -q cyrus-imapd - Is it the case that the package is installed? - - - - Check the system partitions to determine if they are encrypted with the following command: -blkid - -Output will be similar to: -/dev/sda1: UUID=" ab12c3de-4f56-789a-8f33-3850cc8ce3a2 -" TYPE="crypto_LUKS" -/dev/sda2: UUID=" bc98d7ef-6g54-321h-1d24-9870de2ge1a2 -" TYPE="crypto_LUKS" - -The boot partition and pseudo-file systems, such as /proc, /sys, and tmpfs, -are not required to use disk encryption and are not a finding. - Is it the case that partitions do not have a type of crypto_LUKS? - - - - To determine if the system is configured to audit calls to the -renameat system call, run the following command: -$ sudo grep "renameat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify the usrquota option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . usrquota . . . - - Is it the case that the "/home" file system does not have the "usrquota" option set? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "usermod" command with the following command: - -$ sudo auditctl -l | grep usermod - --a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-usermod - Is it the case that the command does not return a line, or the line is commented out? - - - - -Run the following command to determine if the selinuxuser_execstack SELinux boolean is disabled: -$ getsebool selinuxuser_execstack -If properly configured, the output should show the following: -selinuxuser_execstack --> off - Is it the case that selinuxuser_execstack is not disabled? - - - - Inspect /etc/default/grub for any instances of selinux=0 -in the kernel boot arguments. Presence of selinux=0 indicates -that SELinux is disabled at boot time. - Is it the case that SELinux is disabled at boot time? - - - - To determine if the system is configured to audit accesses to -/var/log/audit directory, run the following command: -$ sudo grep "dir=/var/log/audit" /etc/audit/audit.rules -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - If the device or Oracle Linux 9 does not have a camera installed, this requirement is not applicable. - -This requirement is not applicable to mobile devices (smartphones and tablets), where the use of the camera is a local AO decision. - -This requirement is not applicable to dedicated VTC suites located in approved VTC locations that are centrally managed. - -For an external camera, if there is not a method for the operator to manually disconnect the camera at the end of collaborative computing sessions, this is a finding. - -For a built-in camera, the camera must be protected by a camera cover (e.g., laptop camera cover slide) when not in use. If the built-in camera is not protected with a camera cover, or is not physically disabled, this is a finding. - -If the camera is not disconnected, covered, or physically disabled, determine if it is being disabled via software with the following commands: - -Verify the operating system disables the ability to load the uvcvideo kernel module. - -$ sudo grep -r uvcvideo /etc/modprobe.d/* | grep "/bin/true" - -install uvcvideo /bin/true - Is it the case that the command does not return any output, or the line is commented out, and the collaborative computing device has not been authorized for use? - - - - Verify that temporary accounts have been provisioned with an expiration date -of 72 hours. For every temporary account, run the following command to -obtain its account aging and expiration information: -$ sudo chage -l temporary_account_name -Verify each of these accounts has an expiration date set within 72 hours or -as documented. - Is it the case that any temporary accounts have no expiration date set or do not expire within 72 hours? - - - - Verify Oracle Linux 9 audits the execution of privileged functions. - -Check if Oracle Linux 9 is configured to audit the execution of the "execve" system call using the following command: - -$ sudo grep execve /etc/audit/audit.rules - -The output should be the following: - - --a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid --a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid - Is it the case that the command does not return all lines, or the lines are commented out? - - - - If IPv6 is disabled, this is not applicable. - -Inspect the file /etc/sysconfig/ip6tables to determine -the default policy for the INPUT chain. It should be set to DROP: -$ sudo grep ":INPUT" /etc/sysconfig/ip6tables - Is it the case that the default policy for the INPUT chain is not set to DROP? - - - - Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: - -$ sudo grep audit /etc/security/faillock.conf - -audit - Is it the case that the "audit" option is not set, is missing or commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setsebool" command with the following command: - -$ sudo auditctl -l | grep setsebool - --a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -k privileged - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify the system-wide shared library files contained in the following directories have mode "755" or less permissive with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 -perm /022 -type f -exec ls -l {} \; - Is it the case that any system-wide shared library file is found to be group-writable or world-writable? - - - - To check for virtual console entries which permit root login, run the -following command: -$ sudo grep ^vc/[0-9] /etc/securetty -If any output is returned, then root logins over virtual console devices is permitted. - Is it the case that root login over virtual console devices is permitted? - - - - The runtime status of the kernel.randomize_va_space kernel parameter can be queried -by running the following command: -$ sysctl kernel.randomize_va_space -2. - - Is it the case that the correct value is not returned? - - - - Check whether the maximum time period for existing passwords is restricted to days with the following commands: - -$ sudo awk -F: '$5 > 60 {print $1 " " $5}' /etc/shadow - -$ sudo awk -F: '$5 <= 0 {print $1 " " $5}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - Verify the nosuid option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . nosuid . . . - - Is it the case that the "/tmp" file system does not have the "nosuid" option set? - - - - To determine how the SSH daemon's X11Forwarding option is set, run the following command: - -$ sudo grep -i X11Forwarding /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check if UsePrivilegeSeparation is enabled or set correctly, run the -following command: -$ sudo grep UsePrivilegeSeparation /etc/ssh/sshd_config -If configured properly, output should be . - Is it the case that it is commented out or is not enabled? - - - - The file /etc/at.deny should not exist. -This can be checked by running the following - -stat /etc/at.deny - -and the output should be - -stat: cannot stat `/etc/at.deny': No such file or directory - - Is it the case that the file /etc/at.deny exists? - - - - Run the following command to determine if the sudo package is installed: $ rpm -q sudo - Is it the case that the package is not installed? - - - - The runtime status of the kernel.yama.ptrace_scope kernel parameter can be queried -by running the following command: -$ sysctl kernel.yama.ptrace_scope -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.rp_filter kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.rp_filter -1. - - Is it the case that the correct value is not returned? - - - - Run the following command to see what the max sessions number is: -$ sudo grep MaxSessions /etc/ssh/sshd_config -If properly configured, the output should be: -MaxSessions - Is it the case that MaxSessions is not configured or not configured correctly? - - - - To check the group ownership of /etc/crontab, -run the command: -$ ls -lL /etc/crontab -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/crontab does not have a group owner of root? - - - - To check the group ownership of /etc/shells, -run the command: -$ ls -lL /etc/shells -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shells does not have a group owner of root? - - - - To check the ownership of /etc/cron.weekly, -run the command: -$ ls -lL /etc/cron.weekly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.weekly does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_RANDSTRUCT /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was built with the required value? - - - - Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server - Is it the case that the package is installed? - - - - -If the system is configured to prevent the loading of the firewire-core kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the firewire-core kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r firewire-core /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -To check that the rlogin service is disabled in system boot configuration with xinetd, run the following command: -$ chkconfig rlogin --list -Output should indicate the rlogin service has either not been installed, or has been disabled, as shown in the example below: -$ chkconfig rlogin --list - -Note: This output shows SysV services only and does not include native -systemd services. SysV configuration data might be overridden by native -systemd configuration. - -If you want to list systemd services use 'systemctl list-unit-files'. -To see services enabled on particular target use -'systemctl list-dependencies [target]'. - -rlogin off - -To check that the rlogin socket is disabled in system boot configuration with systemd, run the following command: -$ systemctl is-enabled rlogin -Output should indicate the rlogin socket has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled rlogindisabled - -Run the following command to verify rlogin is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active rlogin - -If the socket is not running the command will return the following output: -inactive - -The socket will also be masked, to check that the rlogin is masked, run the following command: -$ sudo systemctl show rlogin | grep "LoadState\|UnitFileState" - -If the socket is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that service and/or socket are running? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PROC_KCORE /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/passwd, -run the command: -$ ls -lL /etc/passwd -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/passwd does not have a group owner of root? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules -The output has to be exactly as follows: -## Successful file modifications (open for write or truncate) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification - Is it the case that the file does not exist or the content differs? - - - - To verify that the Dracut FIPS module is enabled, run the following command: -grep "add_dracutmodules" /etc/dracut.conf.d/40-fips.conf -The output should look like this: -add_dracutmodules+=" fips " - Is it the case that the Dracut FIPS module is not enabled? - - - - To check the ownership of /etc/sudoers, -run the command: -$ ls -lL /etc/sudoers -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sudoers does not have an owner of root? - - - - Verify the umask setting is configured correctly in the /etc/profile file -or scripts within /etc/profile.d directory with the following command: -$ grep "umask" /etc/profile* -umask - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", -or the "umask" parameter is missing or is commented out? - - - - To determine how the SSH daemon's X11Forwarding option is set, run the following command: - -$ sudo grep -i X11Forwarding /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Verify that Oracle Linux 9 is configured to prevent unrestricted mail relaying, -run the following command: -$ sudo postconf -n smtpd_client_restrictions - Is it the case that the "smtpd_client_restrictions" parameter contains any entries other than "permit_mynetworks" and "reject"? - - - - Run the following command to determine if the audit package is installed: $ rpm -q audit - Is it the case that the audit package is not installed? - - - - Inspect /etc/login.defs and ensure that if either -SHA_CRYPT_MIN_ROUNDS or SHA_CRYPT_MAX_ROUNDS -are set, they must have the minimum value of . - Is it the case that it does not? - - - - Inspect the network interfaces assigned to the firewalld trusted zone and verify the -lo interface is listed by running the following command: - -$ sudo firewall-cmd --list-interfaces --zone=trusted - Is it the case that loopback traffic is not trusted? - - - - To check the ownership of /etc/cron.monthly, -run the command: -$ ls -lL /etc/cron.monthly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.monthly does not have an owner of root? - - - - The runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.router_solicitations -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.log_martians kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.log_martians -1. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HARDENED_USERCOPY_FALLBACK /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "semanage" command with the following command: - -$ sudo auditctl -l | grep semanage - --a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if logfile has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults\s*\blogfile\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that logfile is not enabled in sudo? - - - - Verify that core dumps are disabled for all users, run the following command: -$ grep core /etc/security/limits.conf -* hard core 0 - Is it the case that the "core" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core"? - - - - The runtime status of the kernel.core_uses_pid kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_uses_pid -0. - Is it the case that the returned line does not have a value of 0? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/passwd)' - --w /etc/passwd -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_LATENT_ENTROPY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify if the OpenSSH client uses defined MACs in the Crypto Policy, run: -$ grep -i macs /etc/crypto-policies/back-ends/openssh.config -and verify that the line matches: -MACs - Is it the case that Crypto Policy for OpenSSH client is not configured correctly? - - - - -Run the following command to determine if the kerberos_enabled SELinux boolean is enabled: -$ getsebool kerberos_enabled -If properly configured, the output should show the following: -kerberos_enabled --> on - Is it the case that kerberos_enabled is not enabled? - - - - To check the permissions of /etc/passwd-, -run the command: -$ ls -l /etc/passwd- -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/passwd- does not have unix mode -rw-r--r--? - - - - To ensure the X Windows package group is removed, run the following command: - -$ rpm -qi xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland - -For each package mentioned above you should receive following line: -package <package> is not installed - Is it the case that xorg related packages are not removed and run level is not correctly configured? - - - - To verify that execution of the command is being audited, run the following command: -$ sudo grep "path=/usr/sbin/seunshare" /etc/audit/audit.rules /etc/audit/rules.d/* -The output should return something similar to: --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - Is it the case that ? - - - - Run the following command to Verify that the sudoers security policy is configured to use the invoking user's password for privilege escalation: - sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)' -or if cvtsudoers not supported: - sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; -If no results are returned, this is a finding. -If conflicting results are returned, this is a finding. -If "Defaults !targetpw" is not defined, this is a finding. -If "Defaults !rootpw" is not defined, this is a finding. -If "Defaults !runaspw" is not defined, this is a finding. - Is it the case that invoke user passwd when using sudo? - - - - Verify the nodev option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . nodev . . . - - Is it the case that the "/dev/shm" file system does not have the "nodev" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_LIST /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/chrony.keys, -run the command: -$ ls -lL /etc/chrony.keys -If properly configured, the output should indicate the following group-owner: -chrony - Is it the case that /etc/chrony.keys does not have a group owner of chrony? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PANIC_ON_OOPS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the kernel.modules_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.modules_disabled -1. - - Is it the case that the correct value is not returned? - - - - Verify that a separate file system/partition has been created for /var/log with the following command: - -$ mountpoint /var/log - - Is it the case that "/var/log is not a mountpoint" is returned? - - - - To check the group ownership of /etc/group, -run the command: -$ ls -lL /etc/group -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/group does not have a group owner of root? - - - - Verify Oracle Linux 9 disables network management of the chrony daemon with the following command: -$ grep -w cmdport /etc/chrony.conf -cmdport 0 - Is it the case that the "cmdport" option is not set to "0", is commented out, or is missing? - - - - Run the following command to determine if the gnutls-utils package is installed: $ rpm -q gnutls-utils - Is it the case that the package is not installed? - - - - To check that the debug-shell service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled debug-shell -Output should indicate the debug-shell service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled debug-shell disabled - -Run the following command to verify debug-shell is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active debug-shell - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the debug-shell is masked, run the following command: -$ sudo systemctl show debug-shell | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "debug-shell" is loaded and not masked? - - - - To verify if the OpenSSH server uses defined MACs in the Crypto Policy, run: -$ grep -Po '(-oMACs=\S+)' /etc/crypto-policies/back-ends/opensshserver.config -and verify that the line matches: --oMACS= - Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_pinfo -0. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RANDOMIZE_MEMORY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_IPV6 /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 generates an audit record for all uses of the "umount" and system call. -To determine if the system is configured to audit calls to the -"umount" system call, run the following command: -$ sudo grep "umount" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line like the following. --a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -k privileged-umount - Is it the case that the command does not return a line, or the line is commented out? - - - - - -Run the following command to determine the current status of the -syslog-ng service: -$ sudo systemctl is-active syslog-ng -If the service is running, it should return the following: active - Is it the case that the "syslog-ng" service is disabled, masked, or not started.? - - - - -Run the following command to determine if the selinuxuser_execheap SELinux boolean is disabled: -$ getsebool selinuxuser_execheap -If properly configured, the output should show the following: -selinuxuser_execheap --> off - Is it the case that selinuxuser_execheap is not disabled? - - - - Verify that the IPSec service uses the system crypto policy. - -If the ipsec service is not installed is not applicable. +$ grep minlen /etc/security/pwquality.conf -Check to see if the "IPsec" service is active with the following command: - -$ systemctl status ipsec - -ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec -Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) -Active: inactive (dead) - -If the "IPsec" service is active, check to see if it is using the system crypto policy with the following command: - -$ sudo grep include /etc/ipsec.conf /etc/ipsec.d/*.conf - -/etc/ipsec.conf:include /etc/crypto-policies/back-ends/libreswan.config - Is it the case that the "IPsec" service is active and the ipsec configuration file does not contain does not contain <tt>include /etc/crypto-policies/back-ends/libreswan.config</tt>? - - - - -Run the following command to determine if the selinuxuser_execmod SELinux boolean is enabled: -$ getsebool selinuxuser_execmod -If properly configured, the output should show the following: -selinuxuser_execmod --> on - Is it the case that selinuxuser_execmod is not enabled? - - - - To check the ownership of /etc/gshadow-, -run the command: -$ ls -lL /etc/gshadow- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/gshadow- does not have an owner of root? - - - - -If the system is configured to prevent the loading of the cramfs kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the cramfs kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r cramfs /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chsh" command with the following command: - -$ sudo auditctl -l | grep chsh - --a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chsh - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the group ownership of /etc/iptables, -run the command: -$ ls -lL /etc/iptables -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/iptables does not have a group owner of root? - - - - Run the following command to determine if the pcsc-lite package is installed: $ rpm -q pcsc-lite - Is it the case that the package is not installed? - - - - To check for incorrectly labeled device files, run following commands: -$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n" -$ sudo find /dev -context *:unlabeled_t:* \( -type c -o -type b \) -printf "%p %Z\n" -It should produce no output in a well-configured system. - Is it the case that there is output? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine if the system is configured to audit calls to the -finit_module system call, run the following command: -$ sudo grep "finit_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? +minlen = + Is it the case that the command does not return a "minlen" value of "<sub idref="var_password_pam_minlen" />" or greater, does not return a line, or the line is commented out? - - Verify users are provided with feedback on when account accesses last occurred with the following command: - -$ sudo grep pam_lastlog /etc/pam.d/postlogin + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one special character with the following command: -session required pam_lastlog.so showfailed - Is it the case that "pam_lastlog.so" is not properly configured in "/etc/pam.d/postlogin" file? - - - - Verify that DNS servers have been configured properly, perform the following: -$ sudo grep nameserver /etc/resolv.conf - Is it the case that less than two lines are returned that are not commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes mds=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mds=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*mds=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'mds=' -The command should not return any output. - Is it the case that MDS mitigations are not configured appropriately? - - - - Run the following command to determine if the aide package is installed: $ rpm -q aide - Is it the case that the package is not installed? - - - - Run the following command to determine if the rear package is installed: $ rpm -q rear - Is it the case that the package is not installed? - - - - Verify the noexec option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . noexec . . . +$ sudo grep ocredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - Is it the case that the "/home" file system does not have the "noexec" option set? - - - - To check the group ownership of /var/log/messages, -run the command: -$ ls -lL /var/log/messages -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /var/log/messages does not have a group owner of root? - - - - Inspect the file /etc/firewalld/firewalld.conf to determine -the default zone for the firewalld. It should be set to DefaultZone=drop: -$ sudo grep DefaultZone /etc/firewalld/firewalld.conf - Is it the case that the default zone is not set to DROP? - - - - Verify that only the "root" account has a UID "0" assignment with the -following command: -$ awk -F: '$3 == 0 {print $1}' /etc/passwd -root - Is it the case that any accounts other than "root" have a UID of "0"? +ocredit = + Is it the case that value of "ocredit" is a positive number or is commented out? - - Verify the system commands contained in the following directories have mode "755" or less permissive with the following command: + + Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file +and is configured to prohibit password reuse for a minimum of +generations. -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin -perm /022 -exec ls -l {} \; - Is it the case that any system commands are found to be group-writable or world-writable? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "userhelper" command with the following command: +Verify the "/etc/pam.d/password-auth" file with the following command: -$ sudo auditctl -l | grep userhelper +$ grep pam_pwhistory.so /etc/pam.d/password-auth +password pam_pwhistory.so use_authtok remember= --a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -k privileged-userhelper - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the syslog-ng-core package is installed: $ rpm -q syslog-ng-core - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "gpasswd" command with the following command: - -$ sudo auditctl -l | grep gpasswd - --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-gpasswd - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -rmdir system call, run the following command: -$ sudo grep "rmdir" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -unlink system call, run the following command: -$ sudo grep "unlink" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -unlinkat system call, run the following command: -$ sudo grep "unlinkat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -rename system call, run the following command: -$ sudo grep "rename" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -renameat system call, run the following command: -$ sudo grep "renameat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - To check the ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/user.cfg does not have an owner of root? - - - - Verify that Oracle Linux 9 disables the use of user namespaces with the following commands: - -Note: User namespaces are used primarily for Linux containers. If containers are in use, this requirement is not applicable. - -The runtime status of the user.max_user_namespaces kernel parameter can be queried -by running the following command: -$ sysctl user.max_user_namespaces -0. - - Is it the case that the correct value is not returned? - - - - To verify that packages comprising the available updates will be automatically installed by dnf-automatic, run the following command: -$ sudo grep apply_updates /etc/dnf/automatic.conf -The output should return the following: -apply_updates = yes - Is it the case that apply_updates is not set to yes? - - - - Verify that Oracle Linux 9 is configured to notify the SA and/or ISSO (at a minimum) in the event of an audit processing failure with the following command: - -$ sudo grep action_mail_acct /etc/audit/auditd.conf - -action_mail_acct = - Is it the case that the value of the "action_mail_acct" keyword is not set to "<sub idref="var_auditd_action_mail_acct" />" and/or other accounts for security personnel, the "action_mail_acct" keyword is missing, or the retuned line is commented out, ask the system administrator to indicate how they and the ISSO are notified of an audit process failure. If there is no evidence of the proper personnel being notified of an audit processing failure? - - - - To verify that McAfee Endpoint Security for Linux is -running, run the following command: -$ sudo ps -ef | grep -i mfetpd - Is it the case that virus scanning software is not running? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_PTYS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine if the system is configured to audit calls to the -rename system call, run the following command: -$ sudo grep "rename" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify file systems that are used for removable media are mounted with the "nosuid" option with the following command: - -$ sudo more /etc/fstab - -UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 - Is it the case that file system found in "/etc/fstab" refers to removable media and it does not have the "nosuid" option set? - - - - To determine if the system is configured to audit calls to the -mount system call, run the following command: -$ sudo grep "mount" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the ownership of /etc/cron.hourly, -run the command: -$ ls -lL /etc/cron.hourly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.hourly does not have an owner of root? - - - - To check the permissions of /boot/grub2/user.cfg, -run the command: -$ ls -l /boot/grub2/user.cfg -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "passwd" command with the following command: - -$ sudo auditctl -l | grep passwd - --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-passwd - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv4.conf.default.shared_media kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.shared_media -0. - - Is it the case that the correct value is not returned? - - - - Ensure that Oracle Linux 9 verifies correct operation of security functions. -Check if "SELinux" is active and in "" mode with the following command: +Verify the "/etc/security/pwhistory.conf" file using the following command: -$ sudo getenforce +$ grep remember /etc/security/pwhistory.conf +remember = - Is it the case that SELINUX is not set to enforcing? +The pam_pwhistory.so "remember" option must be configured only in one file. + Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in +/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set +with a value less than "<sub idref="var_password_pam_remember" />"? @@ -255627,699 +277705,37 @@ The pam_pwhistory.so "remember" option must be configured only in one file. with a value less than "<sub idref="var_password_pam_remember" />"? - - To verify that Linux Audit logging is enabled for the USBGuard daemon, -run the following command: -$ sudo grep AuditBackend /etc/usbguard/usbguard-daemon.conf -The output should be -AuditBackend=LinuxAudit - Is it the case that AuditBackend is not set to LinuxAudit? + + To check if pam_pwquality.so is enabled in password-auth, run the following command: +$ grep pam_pwquality /etc/pam.d/password-auth +The output should be similar to the following: +password requisite pam_pwquality.so + Is it the case that pam_pwquality.so is not enabled in password-auth? - - To check the permissions of /etc/cron.monthly, -run the command: -$ ls -l /etc/cron.monthly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.monthly does not have unix mode -rwx------? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_COMPAT_VDSO /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify "nftables" is configured to allow rate limits on any connection to the system with the following command: + + Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . -Verify "firewalld" has "nftables" set as the default backend: - -$ sudo grep -i firewallbackend /etc/firewalld/firewalld.conf - -# FirewallBackend -FirewallBackend=nftables - Is it the case that the "nftables" is not set as the "firewallbackend"? +Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: +$ grep retry /etc/security/pwquality.conf + Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? - - To check the group ownership of /etc/issue.net, -run the command: -$ ls -lL /etc/issue.net -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/issue.net does not have a group owner of root? + + To check if pam_pwquality.so is enabled in system-auth, run the following command: +$ grep pam_pwquality /etc/pam.d/system-auth +The output should be similar to the following: +password requisite pam_pwquality.so + Is it the case that pam_pwquality.so is not enabled in system-auth? - - -Run the following command to determine the current status of the -tmp mount: -$ sudo systemctl is-active tmp.mount -If the mount unit is running, it should return the following: active - Is it the case that the tmp.mount unit is masked or disabled? - - - - Verify the nosuid option is configured for the /boot/efi mount point, - run the following command: - $ sudo mount | grep '\s/boot/efi\s' - . . . /boot/efi . . . nosuid . . . - - Is it the case that the "/boot/efi" file system does not have the "nosuid" option set? - - - - To determine if the system is configured to audit calls to the -setxattr system call, run the following command: -$ sudo grep "setxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the group ownership of /etc/selinux, -run the command: -$ ls -lL /etc/selinux -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/selinux does not have a group owner of root? - - - - Verify the SELINUX on Oracle Linux 9 is using the policy with the following command: - -$ sestatus | grep policy - -Loaded policy name: - Is it the case that the loaded policy name is not "<sub idref="var_selinux_policy_name" />"? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_VSYSCALL_NONE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check that the nftables service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled nftables -Output should indicate the nftables service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled nftables disabled - -Run the following command to verify nftables is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active nftables - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the nftables is masked, run the following command: -$ sudo systemctl show nftables | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "nftables" is loaded and not masked? - - - - To check the ownership of /etc/passwd, -run the command: -$ ls -lL /etc/passwd -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/passwd does not have an owner of root? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -$ sudo cat /etc/audit/rules.d/11-loginuid.rules -The output has to be exactly as follows: -## Make the loginuid immutable. This prevents tampering with the auid. ---loginuid-immutable - Is it the case that the file does not exist or the content differs? - - - - To ensure all GIDs referenced in /etc/passwd are defined in /etc/group, -run the following command: -$ sudo pwck -qr -There should be no output. - Is it the case that GIDs referenced in /etc/passwd are returned as not defined in /etc/group? - - - - To determine the status and frequency of logrotate, run the following command: -$ sudo grep logrotate /var/log/cron* -If logrotate is configured properly, output should include references to -/etc/cron.daily. - Is it the case that logrotate is not configured to run daily? - - - - Run the following command to determine if the setroubleshoot-server package is installed: -$ rpm -q setroubleshoot-server - Is it the case that the package is installed? - - - - Verify the nodev option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . nodev . . . - - Is it the case that the "/var/log/audit" file system does not have the "nodev" option set? - - - - To verify the INACTIVE setting, run the following command: -$ grep "INACTIVE" /etc/default/useradd -The output should indicate the INACTIVE configuration option is set -to an appropriate integer as shown in the example below: -$ grep "INACTIVE" /etc/default/useradd -INACTIVE= - Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-keysign" command with the following command: - -$ sudo auditctl -l | grep ssh-keysign - --a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-keysign - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify the audit tools are protected from unauthorized access, deletion, or modification by checking the permissive mode. - -Check the octal permission of each audit tool by running the following command: - -$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - Is it the case that any of these files have more permissive permissions than 0755? - - - - To check the group ownership of /etc/ipsec.conf, -run the command: -$ ls -lL /etc/ipsec.conf -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ipsec.conf does not have a group owner of root? - - - - Verify the operating system audits activities performed during nonlocal -maintenance and diagnostic sessions. Run the following command: -$ sudo auditctl -l | grep sudo.log --w /var/log/sudo.log -p wa -k maintenance - - Is it the case that Audit rule is not present? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to check if the line is present: -grep pam_wheel /etc/pam.d/su -The output should contain the following line: -auth required pam_wheel.so use_uid - Is it the case that the line is not in the file or it is commented? - - - - To check that the kdump service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled kdump -Output should indicate the kdump service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled kdump disabled - -Run the following command to verify kdump is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active kdump - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the kdump is masked, run the following command: -$ sudo systemctl show kdump | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "kdump" is loaded and not masked? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_rtr_pref -0. - - Is it the case that the correct value is not returned? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling autorun-never -If properly configured, the output for autorun-nevershould be true. -To ensure that users cannot enable autorun in GNOME3, run the following: -$ grep 'autorun-never' /etc/dconf/db/local.d/locks/* -If properly configured, the output for autorun-never should be /org/gnome/desktop/media-handling/autorun-never - Is it the case that GNOME autorun is not disabled? - - - - To ensure logs are sent to a remote host, examine the file -/etc/rsyslog.conf. -If using UDP, a line similar to the following should be present: - *.* @ -If using TCP, a line similar to the following should be present: - *.* @@ -If using RELP, a line similar to the following should be present: - *.* :omrelp: - Is it the case that no evidence that the audit logs are being off-loaded to another system or media? - - - - To find SUID files, run the following command: -$ sudo find / -xdev -type f -perm -4000 - Is it the case that only authorized files appear in the output of the find command? - - - - To check the ownership of /var/log/syslog, -run the command: -$ ls -lL /var/log/syslog -If properly configured, the output should indicate the following owner: -syslog - Is it the case that /var/log/syslog does not have an owner of syslog? - - - - To check the group ownership of /etc/gshadow, -run the command: -$ ls -lL /etc/gshadow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/gshadow does not have a group owner of root? - - - - To verify that null passwords cannot be used, run the following command: - -$ grep nullok /etc/pam.d/system-auth /etc/pam.d/password-auth - -If this produces any output, it may be possible to log into accounts -with empty passwords. Remove any instances of the nullok option to -prevent logins with empty passwords. - Is it the case that NULL passwords can be used? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "reboot" command with the following command: - -$ sudo auditctl -l | grep reboot - --a always,exit -F path=/reboot -F perm=x -F auid>=1000 -F auid!=unset -k privileged-reboot - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the group ownership of /var/log/syslog, -run the command: -$ ls -lL /var/log/syslog -If properly configured, the output should indicate the following group-owner: -adm - Is it the case that /var/log/syslog does not have a group owner of adm? - - - - To verify that all user initialization files have a mode of 0740 or -less permissive, run the following command: -$ sudo find /home -type f -name '\.*' \( -perm -0002 -o -perm -0020 \) -There should be no output. - Is it the case that they are not 0740 or more permissive? - - - - To determine if the system is configured to audit calls to the -clock_settime system call, run the following command: -$ sudo grep "clock_settime" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes slab_nomerge=yes, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slab_nomerge=yes.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*slab_nomerge=yes.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'slab_nomerge=yes' -The command should not return any output. - Is it the case that merging of slabs with similar size is enabled? - - - - To verify if the OpenSSH client uses defined Cipher suite in the Crypto Policy, run: -$ grep -i ciphers /etc/crypto-policies/back-ends/openssh.config -and verify that the line matches: -Ciphers - Is it the case that Crypto Policy for OpenSSH client is not configured correctly? - - - - First, check whether the password is defined in either /boot/grub2/user.cfg or -/boot/grub2/grub.cfg. -Run the following commands: -$ sudo grep '^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$' /boot/grub2/user.cfg -$ sudo grep '^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$' /boot/grub2/grub.cfg + + Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . -Second, check that a superuser is defined in /boot/grub2/grub.cfg. -$ sudo grep '^[\s]*set[\s]+superusers=("?)[a-zA-Z_]+\1$' /boot/grub2/grub.cfg - Is it the case that it does not produce any output? - - - - To check the permissions of /var/log/syslog, -run the command: -$ ls -l /var/log/syslog -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /var/log/syslog does not have unix mode -rw-r-----? - - - - To check the group ownership of /etc/cron.allow, -run the command: -$ ls -lL /etc/cron.allow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.allow does not have a group owner of root? - - - - To verify that only security updates will be automatically installed by dnf-automatic, run the following command: -$ sudo grep upgrade_type /etc/dnf/automatic.conf -The output should return the following: -upgrade_type = security - Is it the case that the upgrade_type is not set to security? - - - - The runtime status of the net.core.bpf_jit_harden kernel parameter can be queried -by running the following command: -$ sysctl net.core.bpf_jit_harden -2. - - Is it the case that the correct value is not returned? - - - - Run the following command to see what the timeout interval is: -$ sudo grep ClientAliveInterval /etc/ssh/sshd_config -If properly configured, the output should be: -ClientAliveInterval - Is it the case that it is commented out or not configured properly? - - - - To check the ownership of /etc/passwd-, -run the command: -$ ls -lL /etc/passwd- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/passwd- does not have an owner of root? - - - - To determine if the system is configured to audit calls to the -removexattr system call, run the following command: -$ sudo grep "removexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - The file permissions for all log files written by rsyslog should -be set to 640, or more restrictive. These log files are determined by the -second part of each Rule line in /etc/rsyslog.conf and typically -all appear in /var/log. To see the permissions of a given log -file, run the following command: -$ ls -l LOGFILE -The permissions should be 640, or more restrictive. - Is it the case that the permissions are not correct? - - - - Verify the "umask" setting is configured correctly in the "/etc/csh.cshrc" file with the following command: - -$ grep umask /etc/csh.cshrc - -umask 077 -umask 077 - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BINFMT_MISC /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to ensure that /tmp is configured as a -polyinstantiated directory: -$ sudo grep /tmp /etc/security/namespace.conf -The output should return the following: -/tmp /tmp/tmp-inst/ level root,adm - Is it the case that is not configured? - - - - To check the group ownership of /etc/ipsec.secrets, -run the command: -$ ls -lL /etc/ipsec.secrets -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ipsec.secrets does not have a group owner of root? - - - - To verify that the system will shutdown when auditd fails, -run the following command: -$ sudo grep "\-f " /etc/audit/audit.rules -The output should contain: --f - Is it the case that the system is not configured to shutdown on auditd failures? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STRICT_KERNEL_WRX /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RETPOLINE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Inspect the password section of /etc/pam.d/password-auth -and ensure that the pam_unix.so module is configured to use the argument -: - -$ grep /etc/pam.d/password-auth - Is it the case that it does not? - - - - Verify the system-wide shared library files are owned by "root" with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -user root -exec ls -l {} \; - Is it the case that any system wide shared library file is not owned by root? - - - - To verify that smart cards are enabled in SSSD, run the following command: -$ sudo grep pam_cert_auth /etc/sssd/sssd.conf -If configured properly, output should be -pam_cert_auth = True - - -To verify that smart cards are enabled in PAM files, run the following command: -$ sudo grep -e "auth.*pam_sss\.so.*\(allow_missing_name\|try_cert_auth\)" /etc/pam.d/smartcard-auth /etc/pam.d/system-auth -If configured properly, output should be - -/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name -/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth - - Is it the case that smart cards are not enabled in SSSD? - - - - - -Run the following command to determine the current status of the -ufw service: -$ sudo systemctl is-active ufw -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - Run the following command to check the mode of the system audit logs: -$ sudo grep -iw log_file /etc/audit/auditd.conf -log_file=/var/log/audit/audit.log -$ sudo stat -c "%n %a" /var/log/audit/* -$ sudo ls -l /var/log/audit -Audit logs must be mode 0640 or less permissive. - Is it the case that any permissions are more permissive? - - - - Verify that a separate file system/partition has been created for /var/tmp with the following command: - -$ mountpoint /var/tmp - - Is it the case that "/var/tmp is not a mountpoint" is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "pam_timestamp_check" command with the following command: - -$ sudo auditctl -l | grep pam_timestamp_check - --a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pam_timestamp_check - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -unlinkat system call, run the following command: -$ sudo grep "unlinkat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - - - -To determine if firewalld is configured to allow access - -on port 22/tcp, run the following command(s): - firewall-cmd --list-ports - - -to ssh - firewall-cmd --list-services - -If firewalld is configured to allow access through the firewall, something similar to the following will be output: - -If it is a service: -ssh - - -If it is a port: -22/tcp - - Is it the case that sshd service is not enabled in the proper firewalld zone? - - - - To find world-writable files, run the following command: -$ sudo find / -xdev -type f -perm -002 - Is it the case that there is output? - - - - The runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.arp_ignore -. - - Is it the case that the correct value is not returned? - - - - To verify that Audit Daemon is configured to resolve all uid, gid, syscall, -architecture, and socket address information before writing the event to disk, -run the following command: -$ sudo grep log_format /etc/audit/auditd.conf -The output should return the following: -log_format = ENRICHED - Is it the case that log_format isn't set to ENRICHED? - - - - To check that the screen locks immediately when activated, run the following command: -$ gsettings get org.gnome.desktop.screensaver lock-delay -If properly configured, the output should be 'uint32 '. - Is it the case that the screensaver lock delay is missing, or is set to a value greater than <sub idref="var_screensaver_lock_delay" />? - - - - The runtime status of the kernel.dmesg_restrict kernel parameter can be queried -by running the following command: -$ sysctl kernel.dmesg_restrict -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_ra kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra -0. - - Is it the case that the correct value is not returned? +Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: +$ grep retry /etc/security/pwquality.conf + Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? @@ -256333,68 +277749,29 @@ ucredit = -1 Is it the case that the value of "ucredit" is a positive number or is commented out? - - Verify that a separate file system/partition has been created for /var/log/audit with the following command: + + To verify the password reuse setting is compliant, run the following command: +$ grep remember /etc/pam.d/system-auth +The output should show the following at the end of the line: +remember= -$ mountpoint /var/log/audit - Is it the case that "/var/log/audit is not a mountpoint" is returned? +In newer systems, the pam_pwhistory PAM module options can also be set in +"/etc/security/pwhistory.conf" file. Use the following command to verify: +$ grep remember /etc/security/pwhistory.conf +remember = + +The pam_pwhistory remember option must be configured only in one file. + Is it the case that the value of remember is not equal to or greater than the expected value? - - The runtime status of the fs.protected_hardlinks kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_hardlinks -1. + + To verify the number of rounds for the password hashing algorithm is configured, run the following command: +$ sudo grep rounds /etc/pam.d/password-auth +The output should show the following match: - Is it the case that the correct value is not returned? - - - - Verify that yum verifies the signature of local packages prior to install with the following command: - -$ grep localpkg_gpgcheck /etc/yum.conf - -localpkg_gpgcheck=1 - -If "localpkg_gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. - Is it the case that there is no process to validate certificates for local packages that is approved by the organization? - - - - - -Run the following command to determine the current status of the -usbguard service: -$ sudo systemctl is-active usbguard -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - To determine if the system is configured to audit changes to its SELinux -configuration files, run the following command: -$ sudo auditctl -l | grep "dir=/usr/share/selinux" -If the system is configured to watch for changes to its SELinux -configuration, a line should be returned (including -perm=wa indicating permissions that are watched). - Is it the case that the system is not configured to audit attempts to change the MAC policy? - - - - -Check if SSSD allows cached authentications with the following command: - -$ sudo grep cache_credentials /etc/sssd/sssd.conf -cache_credentials = true - -If "cache_credentials" is set to "false" or is missing no further checks are required. - -To verify that SSSD expires offline credentials, run the following command: -$ sudo grep offline_credentials_expiration /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf -If configured properly, output should be -offline_credentials_expiration = 1 - Is it the case that it does not exist or is not configured properly? +password sufficient pam_unix.so sha512 rounds= + Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? @@ -256405,392 +277782,364 @@ password sufficient pam_unix.so sha512 rounds= Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_CREDENTIALS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The following command will list which files on the system have ownership different from what -is expected by the RPM database: -$ rpm -Va | rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' - Is it the case that there is output? - - - - To check that the snmpd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled snmpd -Output should indicate the snmpd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled snmpd disabled + + Check whether the maximum time period for existing passwords is restricted to days with the following commands: -Run the following command to verify snmpd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active snmpd +$ sudo awk -F: '$5 > 60 {print $1 " " $5}' /etc/shadow -If the service is not running the command will return the following output: -inactive +$ sudo awk -F: '$5 <= 0 {print $1 " " $5}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Check whether the maximum time period for root account password is restricted to days with the following commands: -The service will also be masked, to check that the snmpd is masked, run the following command: -$ sudo systemctl show snmpd | grep "LoadState\|UnitFileState" +$ sudo awk -F: '$1 == "root" {print $1 " " $5}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Verify that Oracle Linux 9 has configured the minimum time period between password changes for each user account is one day or greater with the following command: -If the service is masked the command will return the following outputs: +$ sudo awk -F: '$4 < 1 {print $1 " " $4}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Verify that Oracle Linux 9 set the days of warning before a password expires to + or more for users with a +password: -LoadState=masked +$ sudo awk -F: '$6 || $6 == "" {print $1}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + To check the password warning age, run the command: +$ grep PASS_WARN_AGE /etc/login.defs +The profile requirement is . + Is it the case that it is not set to the required value? + + + + Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: -UnitFileState=masked - Is it the case that the "snmpd" is loaded and not masked? - - - - The following command will list which files on the system have file hashes different from what -is expected by the RPM database. -$ rpm -Va --noconfig | awk '$1 ~ /..5/' - Is it the case that there is output? - - - - To check the group ownership of /etc/ssh/sshd_config, -run the command: -$ ls -lL /etc/ssh/sshd_config -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/sshd_config does not have a group owner of root? - - - - Run the following command to determine if the crypto-policies package is installed: $ rpm -q crypto-policies - Is it the case that the package is not installed? - - - - Make sure that the kernel is not disabling SMEP with the following -commands. -grep -q nosmep /boot/config-`uname -r` -If the command returns a line, it means that SMEP is being disabled. - Is it the case that the kernel is configured to disable SMEP? - - - - Run the following command to determine if the audispd-plugins package is installed: $ rpm -q audispd-plugins - Is it the case that the package is not installed? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes slub_debug=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slub_debug=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*slub_debug=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'slub_debug=' -The command should not return any output. - Is it the case that SLUB/SLAB poisoning is not enabled? - - - - To check the group ownership of /etc/shadow-, -run the command: -$ ls -lL /etc/shadow- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shadow- does not have a group owner of root? - - - - Verify the operating system encrypts audit records off-loaded onto a different system -or media from the system being audited with the following commands: +$ sudo grep audit /etc/security/faillock.conf -$ sudo grep -i '$ActionSendStreamDriverMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf +audit + Is it the case that the "audit" option is not set, is missing or commented out? + + + + Verify Oracle Linux 9 is configured to lock an account after +unsuccessful logon attempts with the command: -The output should be: +$ grep 'deny =' /etc/security/faillock.conf +deny = . + Is it the case that the "deny" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_deny" />" +or less (but not "0"), is missing or commented out? + + + + Verify Oracle Linux 9 is configured to lock the root account after +unsuccessful logon attempts with the command: -/etc/rsyslog.conf:$ActionSendStreamDriverMode 1 - Is it the case that rsyslogd ActionSendStreamDriverMode is not set to 1? +$ grep even_deny_root /etc/security/faillock.conf +even_deny_root + Is it the case that the "even_deny_root" option is not set, is missing or commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_VMAP_STACK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? + + To ensure the tally directory is configured correctly, run the following command: +$ sudo grep 'dir =' /etc/security/faillock.conf +The output should show that dir is set to something other than "/var/run/faillock" + Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - To check the group ownership of /var/log, -run the command: -$ ls -lL /var/log -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /var/log does not have a group owner of root? - - - - To verify if the OpenSSH Client uses defined Crypto Policy, run: -$ cat /etc/ssh/ssh_config.d/02-ospp.conf -and verify that the line matches -Match final all -RekeyLimit 512M 1h -GSSAPIAuthentication no -Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc -PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 -MACs hmac-sha2-512,hmac-sha2-256 -KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1 - Is it the case that Crypto Policy for OpenSSH Client is not configured according to CC requirements? - - - - To check the permissions of /etc/gshadow-, -run the command: -$ ls -l /etc/gshadow- -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/gshadow- does not have unix mode ----------? - - - - To verify all squashing has been disabled, run the following command: -$ grep all_squash /etc/exports - Is it the case that there is output? - - - - Verify the pam_faillock.so module is present in the "/etc/pam.d/system-auth" file: + + To ensure the failed password attempt policy is configured correctly, run the following command: -$ sudo grep pam_faillock.so /etc/pam.d/system-auth - -auth required pam_faillock.so preauth -auth required pam_faillock.so authfail -account required pam_faillock.so - Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/system-auth" file with the "preauth" line listed before pam_unix.so? +$ grep fail_interval /etc/security/faillock.conf +The output should show fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. + Is it the case that the "fail_interval" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_fail_interval" />" +or less (but not "0"), the line is commented out, or the line is missing? - - To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + + Verify Oracle Linux 9 is configured to lock an account until released by an administrator +after unsuccessful logon +attempts with the command: -$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? +$ grep 'unlock_time =' /etc/security/faillock.conf +unlock_time = + Is it the case that the "unlock_time" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_unlock_time" />", +the line is missing, or commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SYN_COOKIES /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the ownership of /etc/group-, -run the command: -$ ls -lL /etc/group- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/group- does not have an owner of root? - - - - To verify that Audit Daemon is configured to record the computer node -name in the audit events, run the following command: -$ sudo grep name_format /etc/audit/auditd.conf + + Run the following command to ensure that /tmp is configured as a +polyinstantiated directory: +$ sudo grep /tmp /etc/security/namespace.conf The output should return the following: -name_format = - Is it the case that name_format isn't set to <sub idref="var_auditd_name_format" />? +/tmp /tmp/tmp-inst/ level root,adm + Is it the case that is not configured? - - -To check that the telnet service is disabled in system boot configuration with xinetd, run the following command: -$ chkconfig telnet --list -Output should indicate the telnet service has either not been installed, or has been disabled, as shown in the example below: -$ chkconfig telnet --list - -Note: This output shows SysV services only and does not include native -systemd services. SysV configuration data might be overridden by native -systemd configuration. - -If you want to list systemd services use 'systemctl list-unit-files'. -To see services enabled on particular target use -'systemctl list-dependencies [target]'. - -telnet off - -To check that the telnet socket is disabled in system boot configuration with systemd, run the following command: -$ systemctl is-enabled telnet -Output should indicate the telnet socket has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled telnetdisabled - -Run the following command to verify telnet is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active telnet - -If the socket is not running the command will return the following output: -inactive - -The socket will also be masked, to check that the telnet is masked, run the following command: -$ sudo systemctl show telnet | grep "LoadState\|UnitFileState" - -If the socket is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that service and/or socket are running? + + Run the following command to ensure that /var/tmp is configured as a +polyinstantiated directory: +$ sudo grep /var/tmp /etc/security/namespace.conf +The output should return the following: +/var/tmp /var/tmp/tmp-inst/ level root,adm + Is it the case that is not configured? - - To check the permissions of /etc/selinux, -run the command: -$ ls -l /etc/selinux -If properly configured, the output should indicate the following permissions: -0755 - Is it the case that /etc/selinux does not have unix mode 0755? + + To verify that root's primary group is zero run the following command: + + grep '^root:' /etc/passwd | cut -d : -f 4 + +The command should return: + +0 + + Is it the case that root has a primary gid not equal to zero? - - The runtime status of the kernel.perf_event_paranoid kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_event_paranoid -2. - - Is it the case that the correct value is not returned? + + To ensure write permissions are disabled for group and other + for each element in root's path, run the following command: +# ls -ld DIR + Is it the case that group or other write permissions exist? - - To determine if the system is configured to audit calls to the -lremovexattr system call, run the following command: -$ sudo grep "lremovexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. + + Verify that Oracle Linux 9 's INACTIVE conforms to site policy (no more than 30 days) with the following command: - Is it the case that no line is returned? +$ sudo awk -F: '$7 > 30 {print $1 " " $7}' /etc/shadow + Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - To determine how the SSH daemon's Banner option is set, run the following command: + + Run the following command to ensure the TMOUT value is configured for all users +on the system: -$ sudo grep -i Banner /etc/ssh/sshd_config +$ sudo grep TMOUT /etc/profile /etc/profile.d/*.sh -If a line indicating /etc/issue is returned, then the required value is set. - - Is it the case that the required value is not set? +The output should return the following: +TMOUT= + Is it the case that the TMOUT value is not configured, is set to 0, or is not less than or equal to the expected setting? - - Verify the audit tools are owned by "root" to prevent any unauthorized access, deletion, or modification. + + Verify the umask setting is configured correctly in the /etc/bashrc file with the following command: -Check the owner of each audit tool by running the following command: +$ sudo grep "umask" /etc/bashrc -$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - -root /sbin/auditctl -root /sbin/aureport -root /sbin/ausearch -root /sbin/autrace -root /sbin/auditd -root /sbin/rsyslogd -root /sbin/augenrules - Is it the case that any audit tools are not owned by root? +umask + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - To determine if the system is configured to audit calls to the -unlink system call, run the following command: -$ sudo grep "unlink" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. + + Verify the "umask" setting is configured correctly in the "/etc/csh.cshrc" file with the following command: - Is it the case that no line is returned? +$ grep umask /etc/csh.cshrc + +umask 077 +umask 077 + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - Display the contents of the file /etc/systemd/logind.conf: -cat /etc/systemd/logind.conf -Ensure that there is a section [login] which contains the -configuration StopIdleSessionSec=. - Is it the case that the option is not configured? + + Verify Oracle Linux 9 defines default permissions for all authenticated users in such a way that the user can only read and modify their own files with the following command: + +# grep -i umask /etc/login.defs + +UMASK + Is it the case that the value for the "UMASK" parameter is not "<sub idref="var_accounts_user_umask" />", or the "UMASK" parameter is missing or is commented out? - - Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. - -Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: - -$ sudo grep disk_error_action /etc/audit/auditd.conf - -disk_error_action = - -If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. - Is it the case that there is no evidence of appropriate action? + + Verify the umask setting is configured correctly in the /etc/profile file +or scripts within /etc/profile.d directory with the following command: +$ grep "umask" /etc/profile* +umask + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", +or the "umask" parameter is missing or is commented out? - - To ensure screen locking on smartcard removal is enabled, run the following command: -$ grep removal-action /etc/dconf/db/local.d/* -The output should be 'lock-screen'. -To ensure that users cannot disable screen locking on smartcard removal, run the following: -$ grep removal-action /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/settings-daemon/peripherals/smartcard/removal-action - Is it the case that removal-action has not been configured? - - - - To determine if the system is configured to audit changes to its SELinux -configuration files, run the following command: -$ sudo auditctl -l | grep "dir=/etc/selinux" -If the system is configured to watch for changes to its SELinux -configuration, a line should be returned (including -perm=wa indicating permissions that are watched). - Is it the case that the system is not configured to audit attempts to change the MAC policy? - - - - To check the permissions of /etc/ipsec.secrets, -run the command: -$ ls -l /etc/ipsec.secrets -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/ipsec.secrets does not have unix mode 0644? - - - - The runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_redirects -0. + + Verify that the default umask for all local interactive users is "077". - Is it the case that the correct value is not returned? +Identify the locations of all local interactive user home directories by looking at the "/etc/passwd" file. + +Check all local interactive user initialization files for interactive users with the following command: + +Note: The example is for a system that is configured to create users home directories in the "/home" directory. + +$ sudo find /home -maxdepth 2 -type f -name ".[^.]*" -exec grep -iH -d skip --exclude=.bash_history umask {} \; + +/home/wadea/.bash_history:grep -i umask /etc/bashrc /etc/csh.cshrc /etc/profile +/home/wadea/.bash_history:grep -i umask /etc/login.defs + Is it the case that any local interactive user initialization files are found to have a umask statement that sets a value less restrictive than "077"? - - To determine how the SSH daemon's PermitRootLogin option is set, run the following command: - -$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? + + To verify the local initialization files of all local interactive users are group- +owned by the appropriate user, inspect the primary group of the respective +users in /etc/passwd and verify all initialization files under the +respective users home directory. Check the group owner of all local interactive users +initialization files. + Is it the case that they are not? - - To check the group ownership of /etc/ssh/*.pub, -run the command: -$ ls -lL /etc/ssh/*.pub -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/*.pub does not have a group owner of root? + + Verify that local initialization files do not execute world-writable programs with the following command: + +Note: The example will be for a system that is configured to create user home directories in the "/home" directory. + +$ sudo find /home -perm -002 -type f -name ".[^.]*" -exec ls -ld {} \; + Is it the case that any local initialization files are found to reference world-writable files? + + + + To verify all local initialization files for interactive users are owned by the +primary user, run the following command: +$ sudo ls -al /home/USER/.* +The user initialization files should be owned by USER. + Is it the case that they are not? + + + + Verify that all local interactive user initialization file executable search path statements do not contain statements that will reference a working directory other than user home directories with the following commands: + +$ sudo grep -i path= /home/*/.* + +/home/[localinteractiveuser]/.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin + Is it the case that any local interactive user initialization files have executable search path statements that include directories outside of their home directory and is not documented with the ISSO as an operational requirement? + + + + Verify that interactive users on the system have a home directory assigned with the following command: + +$ sudo awk -F: '($3>=1000)&&($7 !~ /nologin/){print $1, $3, $6}' /etc/passwd + +Inspect the output and verify that all interactive users (normally users with a UID greater than 1000) have a home directory defined. + Is it the case that users home directory is not defined? + + + + Verify the assigned home directories of all interactive users on the system exist with the following command: + +$ sudo pwck -r + +user 'mailnull': directory 'var/spool/mqueue' does not exist + +The output should not return any interactive users. + Is it the case that users home directory does not exist? + + + + To verify all files and directories in interactive user home directory are +group-owned by a group the user is a member of, run the +following command: +$ sudo ls -lLR /home/USER + Is it the case that the group ownership is incorrect? + + + + To verify all files and directories in a local interactive user's +home directory have a valid owner, run the following command: +$ sudo ls -lLR /home/USER + Is it the case that the user ownership is incorrect? + + + + To verify all files and directories contained in interactive user home +directory, excluding local initialization files, have a mode of 0750, +run the following command: +$ sudo ls -lLR /home/USER + Is it the case that home directory files or folders have incorrect permissions? + + + + To verify that McAfee Endpoint Security for Linux is +running, run the following command: +$ sudo ps -ef | grep -i mfetpd + Is it the case that virus scanning software is not running? + + + + To find the location of the AIDE database file, run the following command: +$ sudo ls -l DBDIR/database_file_name + Is it the case that there is no database file? + + + + Check that AIDE is properly configured to protect the integrity of the +audit tools by running the following command: + +# sudo cat /etc/aide.conf | grep /usr/sbin/au + +/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 + +/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 + + +If AIDE is configured properly to protect the integrity of the audit tools, +all lines listed above will be returned from the command. + +If one or more lines are missing, this is a finding. + Is it the case that integrity checks of the audit tools are missing or incomplete? + + + + Verify the operating system routinely checks the baseline configuration for unauthorized changes. + +To determine that periodic AIDE execution has been scheduled, run the following command: +$ grep aide /etc/crontab +The output should return something similar to the following: +05 4 * * * root /usr/sbin/aide --check + +NOTE: The usage of special cron times, such as @daily or @weekly, is acceptable. + Is it the case that AIDE is not configured to scan periodically? + + + + To determine that periodic AIDE execution has been scheduled, run the following command: + +$ grep aide /etc/crontab +The output should return something similar to the following: +05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost +The email address that the notifications are sent to can be changed by overriding +. + Is it the case that AIDE has not been configured or has not been configured to notify personnel of scan details? + + + + To determine that AIDE is configured for FIPS 140-2 file hashing, run the following command: +$ grep sha512 /etc/aide.conf +Verify that the sha512 option is added to the correct ruleset. + Is it the case that the sha512 option is missing or not added to the correct ruleset? + + + + To determine that AIDE is verifying ACLs, run the following command: +$ grep acl /etc/aide.conf +Verify that the acl option is added to the correct ruleset. + Is it the case that the acl option is missing or not added to the correct ruleset? + + + + To determine that AIDE is verifying extended file attributes, run the following command: +$ grep xattrs /etc/aide.conf +Verify that the xattrs option is added to the correct ruleset. + Is it the case that the xattrs option is missing or not added to the correct ruleset? @@ -256805,384 +278154,68 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - Verify the noexec option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . noexec . . . - - Is it the case that the "/var" file system does not have the "noexec" option set? - - - - The telnet package can be removed with the following command: $ sudo yum erase telnet - Is it the case that ? - - - - To determine how the SSH daemon's LogLevel option is set, run the following command: - -$ sudo grep -i LogLevel /etc/ssh/sshd_config - -If a line indicating VERBOSE is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - The runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.router_solicitations -0. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STRICT_MODULE_RWX /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Check whether the maximum time period for root account password is restricted to days with the following commands: - -$ sudo awk -F: '$1 == "root" {print $1 " " $5}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_defrtr -0. - - Is it the case that the correct value is not returned? - - - - To determine how the SSH daemon's AllowTcpForwarding option is set, run the following command: - -$ sudo grep -i AllowTcpForwarding /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - Is it the case that The AllowTcpForwarding option exists and is disabled? - - - - To check the ownership of /etc/ssh/*_key, -run the command: -$ ls -lL /etc/ssh/*_key -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/*_key does not have an owner of root? - - - - Verify Oracle Linux 9 for PKI-based authentication has valid certificates by constructing a -certification path (which includes status information) to an accepted trust anchor. - -Check that the system has a valid DoD root CA installed with the following command: - -$ sudo openssl x509 -text -in /etc/sssd/pki/sssd_auth_ca_db.pem - -Certificate: -Data: -Version: 3 (0x2) -Serial Number: 1 (0x1) -Signature Algorithm: sha256WithRSAEncryption -Issuer: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 -Validity -Not Before: Mar 20 18:46:41 2012 GMT -Not After : Dec 30 18:46:41 2029 GMT -Subject: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 -Subject Public Key Info: -Public Key Algorithm: rsaEncryption - Is it the case that root CA file is not a DoD-issued certificate with a valid date and installed in the /etc/sssd/pki/sssd_auth_ca_db.pem location? - - - - Verify the value of the "maxrepeat" option in "/etc/security/pwquality.conf" with the following command: - -$ grep maxrepeat /etc/security/pwquality.conf - -maxrepeat = - Is it the case that the value of "maxrepeat" is set to more than "<sub idref="var_password_pam_maxrepeat" />" or is commented out? - - - - To determine if use_pty has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\buse_pty\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that use_pty is not enabled in sudo? - - - - -Run the following command to get the current configured value for secure_mode_insmod -SELinux boolean: -$ getsebool secure_mode_insmod -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that secure_mode_insmod is not set as expected? - - - + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/43-module-load.rules +cat /etc/audit/rules.d/30-ospp-v42-3-access-success.rules The output has to be exactly as follows: -## These rules watch for kernel module insertion. By monitoring -## the syscall, we do not need any watches on programs. --a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load --a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load --a always,exit -F arch=b32 -S delete_module -F key=module-unload --a always,exit -F arch=b64 -S delete_module -F key=module-unload +## Successful file access (any other opens) This has to go last. +## These next two are likely to result in a whole lot of events +-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access +-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access Is it the case that the file does not exist or the content differs? - - To check the permissions of /etc/ssh/*_key, -run the command: -$ ls -l /etc/ssh/*_key -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/ssh/*_key does not have unix mode -rw-------? - - - - Find the list of alias maps used by the Postfix mail server: -$ sudo postconf alias_maps -Query the Postfix alias maps for an alias for the root user: -$ sudo postmap -q root hash:/etc/aliases -The output should return an alias. - Is it the case that the alias is not set? - - - - To check the group ownership of /etc/cron.d, -run the command: -$ ls -lL /etc/cron.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.d does not have a group owner of root? - - - - Verify that the system is integrated with a centralized authentication mechanism -such as as Active Directory, Kerberos, Directory Server, etc. that has -automated account mechanisms in place. - Is it the case that the system is not using a centralized authentication mechanism, or it is not automated? - - - - To check the permissions of /etc/cron.allow, -run the command: -$ ls -l /etc/cron.allow -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/cron.allow does not have unix mode -rw-r-----? - - - - To determine if the users are allowed to run commands as root, run the following commands: -$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s]' /etc/sudoers /etc/sudoers.d/ -and -$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\)' /etc/sudoers /etc/sudoers.d/ -Both commands should return no output. - Is it the case that /etc/sudoers file contains rules that allow non-root users to run commands as root? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/10-base-config.rules +The output has to be exactly as follows: +## First rule - delete all +-D -Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: +## Increase the buffers to survive stress events. +## Make this bigger for busy systems +-b 8192 -$ sudo grep disk_full_action /etc/audit/auditd.conf +## This determine how long to wait in burst of events +--backlog_wait_time 60000 -disk_full_action = - -If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. - Is it the case that there is no evidence of appropriate action? +## Set failure mode to syslog +-f 1 + Is it the case that the file does not exist or the content differs? - - The runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_source_route -0. - - Is it the case that the correct value is not returned? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules +The output has to be exactly as follows: +## Unsuccessful file creation (open with O_CREAT) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create + Is it the case that the file does not exist or the content differs? - - Verify that Oracle Linux 9 is configured to audit the execution of the "mount" command with the following command: - -$ sudo auditctl -l | grep mount - --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-mount - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the policycoreutils package is installed: $ rpm -q policycoreutils - Is it the case that the policycoreutils package is not installed? - - - - To check if the installed Operating System is 64-bit, run the following command: -$ uname -m -The output should be one of the following: x86_64, aarch64, ppc64le or s390x. -If the output is i686 or i386 the operating system is 32-bit. -Check if the installed CPU supports 64-bit operating systems by running the following command: -$ lscpu | grep "CPU op-mode" -If the output contains 64bit, the CPU supports 64-bit operating systems. - Is it the case that the installed operating sytem is 32-bit but the CPU supports operation in 64-bit? - - - - To determine that periodic AIDE execution has been scheduled, run the following command: - -$ grep aide /etc/crontab -The output should return something similar to the following: -05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost -The email address that the notifications are sent to can be changed by overriding -. - Is it the case that AIDE has not been configured or has not been configured to notify personnel of scan details? - - - - To check if the system login banner is compliant, run the following command: -$ cat /etc/issue.net - Is it the case that it does not display the required banner? - - - - Find the list of alias maps used by the Postfix mail server: -$ sudo postconf alias_maps -Query the Postfix alias maps for an alias for the postmaster user: -$ sudo postmap -q postmaster hash:/etc/aliases -The output should return root. - Is it the case that the alias is not set or is not root? - - - - Run the following command to determine if the chrony package is installed: $ rpm -q chrony - Is it the case that the package is not installed? - - - - The runtime status of the kernel.pid_max kernel parameter can be queried -by running the following command: -$ sysctl kernel.pid_max -65536. - - Is it the case that the correct value is not returned? - - - - To check the permissions of /var/log, -run the command: -$ ls -l /var/log -If properly configured, the output should indicate the following permissions: -drwxr-xr-x - Is it the case that /var/log does not have unix mode drwxr-xr-x? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_STACKLEAK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify that FIPS mode is enabled properly, run the following command: -cat /proc/sys/crypto/fips_enabled -The output be must: -1 - Is it the case that FIPS mode is not enabled? - - - - To verify that null passwords cannot be used, run the following command: -$ sudo awk -F: '!$2 {print $1}' /etc/shadow -If this produces any output, it may be possible to log into accounts -with empty passwords. - Is it the case that Blank or NULL passwords can be used? - - - - The following command will locate the mount points related to local devices: -$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) - -The following command will show files which do not belong to a valid user: -$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null - -Replace MOUNTPOINT by the mount points listed by the fist command. - -No files without a valid user should be located. - Is it the case that files exist that are not owned by a valid user? - - - - Run the following command to determine if the usbguard package is installed: $ rpm -q usbguard - Is it the case that the package is not installed? - - - - To determine if NOEXEC has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\bnoexec\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that noexec is not enabled in sudo? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "postqueue" command with the following command: - -$ sudo auditctl -l | grep postqueue - --a always,exit -F path=/usr/bin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postqueue - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the scap-security-guide package is installed: $ rpm -q scap-security-guide - Is it the case that the package is not installed? - - - - The runtime status of the kernel.core_pattern kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_pattern | cat -A -kernel.core_pattern = $ - - Is it the case that the returned line does not have an empty string? - - - - The runtime status of the kernel.perf_cpu_time_max_percent kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_cpu_time_max_percent -1. - - Is it the case that the correct value is not returned? - - - - To verify the boot loader superuser account has been set, run the following -command: -sudo grep -A1 "superusers" /boot/grub2/grub.cfg -The output should show the following: -set superusers="superusers-account" -export superusers -where superusers-account is the actual account name different from common names like root, -admin, or administrator and different from any other existing user name. - Is it the case that superuser account is not set or is set to root, admin, administrator or any other existing user name? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-1-create-success.rules +The output has to be exactly as follows: +## Successful file creation (open with O_CREAT) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create + Is it the case that the file does not exist or the content differs? @@ -257197,652 +278230,23 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - To check if pam_pwquality.so is enabled in password-auth, run the following command: -$ grep pam_pwquality /etc/pam.d/password-auth -The output should be similar to the following: -password requisite pam_pwquality.so - Is it the case that pam_pwquality.so is not enabled in password-auth? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules +The output has to be exactly as follows: +## Successful file delete +-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete +-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete + Is it the case that the file does not exist or the content differs? - - To determine if arguments that commands can be executed with are restricted, run the following command: -$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$))' /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that /etc/sudoers file contains user specifications that allow execution of commands with any arguments? - - - - To check that the avahi-daemon service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled avahi-daemon -Output should indicate the avahi-daemon service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled avahi-daemon disabled - -Run the following command to verify avahi-daemon is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active avahi-daemon - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the avahi-daemon is masked, run the following command: -$ sudo systemctl show avahi-daemon | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "avahi-daemon" is loaded and not masked? - - - - Run the following command to check if the group exists: -grep /etc/group -The output should contain the following line: -:x: - Is it the case that group exists and has no user members? - - - - The runtime status of the kernel.core_pattern kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_pattern -|/bin/false. - - Is it the case that the returned line does not have a value of "|/bin/false", or a line is not -returned and the need for core dumps is not documented with the Information -System Security Officer (ISSO) as an operational requirement? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/gshadow" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/gshadow)' - --w /etc/gshadow -p wa -k identity - -If the command does not return a line, or the line is commented out, this is a finding. - Is it the case that the system is not configured to audit account changes? - - - - To determine how the SSH daemon's X11UseLocalhost option is set, run the following command: - -$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - Is it the case that the display proxy is listening on wildcard address? - - - - Verify the noexec option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . noexec . . . - - Is it the case that the "/dev/shm" file system does not have the "noexec" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PANIC_TIMEOUT /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the net.ipv6.conf.default.max_addresses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.max_addresses -1. - - Is it the case that the correct value is not returned? - - - - To check the ownership of /etc/chrony.keys, -run the command: -$ ls -lL /etc/chrony.keys -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/chrony.keys does not have an owner of root? - - - - To determine if the system is configured to audit calls to the -fremovexattr system call, run the following command: -$ sudo grep "fremovexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/group" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/group)' - --w /etc/group -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv4.ip_forward kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.ip_forward -0. -The ability to forward packets is only appropriate for routers. - Is it the case that the correct value is not returned? - - - - - -Run the following command to determine the current status of the -pcscd service: -$ sudo systemctl is-active pcscd -If the service is running, it should return the following: active - Is it the case that the pcscd service is not enabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the permissions of /etc/passwd, -run the command: -$ ls -l /etc/passwd -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/passwd does not have unix mode -rw-r--r--? - - - - Inspect the password section of /etc/pam.d/system-auth -and ensure that the pam_unix.so module is configured to use the argument -: - -$ sudo grep "^password.*pam_unix\.so.*" /etc/pam.d/system-auth - -password sufficient pam_unix.so - Is it the case that "<sub idref="var_password_hashing_algorithm_pam" />" is missing, or is commented out? - - - - Verify that the system backups user data. - Is it the case that it is not? - - - - To determine if NOPASSWD has been configured for the vdsm user for sudo, -run the following command: -$ sudo grep -ri nopasswd /etc/sudoers.d/ -The command should return output only for the vdsm user. - Is it the case that nopasswd is set for any users beyond vdsm? - - - - Run the following command to determine if the rsyslog-gnutls package is installed: -$ rpm -q rsyslog-gnutls - Is it the case that the package is installed? - - - - To verify the audispd's syslog plugin is active, run the following command: -$ sudo grep active /etc/audit/plugins.d/syslog.conf -If the plugin is active, the output will show yes. - Is it the case that it is not activated? - - - - To check the permissions of /etc/group-, -run the command: -$ ls -l /etc/group- -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/group- does not have unix mode -rw-r--r--? - - - - To check the ownership of /boot/System.map*, -run the command: -$ ls -lL /boot/System.map* -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/System.map* does not have an owner of root? - - - - Verify the noexec option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . noexec . . . - - Is it the case that the "/var/tmp" file system does not have the "noexec" option set? - - - - To check that the squid service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled squid -Output should indicate the squid service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled squid disabled - -Run the following command to verify squid is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active squid - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the squid is masked, run the following command: -$ sudo systemctl show squid | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "squid" is loaded and not masked? - - - - To check the permissions of /etc/crontab, -run the command: -$ ls -l /etc/crontab -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/crontab does not have unix mode -rw-------? - - - - To determine if !authenticate has not been configured for sudo, run the following command: -$ sudo grep -r \!authenticate /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that !authenticate is specified in the sudo config files? - - - - Check group owners of the system audit logs. - -First, determine where the audit log file is located. - -$ sudo grep -iw ^log_file /etc/audit/auditd.conf -log_file = /var/log/audit/audit.log - -The log_file option specifies the audit log file path. -If the log_file option isn't defined, check all files within /var/log/audit directory. - - -Then, determine the audit log group by running the following command: -$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf - - -Then, check that the audit log file is owned by the correct group. -Run the following command to display the owner of the audit log file: - -$ sudo stat -c "%n %G" log_file - - -The audit log file must be owned by the log_group or by root if the log_group is not specified. - Is it the case that audit log files are owned by incorrect group? - - - - Determine if "sudoers" file restricts sudo access run the following commands: -$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* -$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* - Is it the case that either of the commands returned a line? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "init" command with the following command: - -$ sudo auditctl -l | grep init - --a always,exit -F path=/init -F perm=x -F auid>=1000 -F auid!=unset -k privileged-init - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the group ownership of /etc/group-, -run the command: -$ ls -lL /etc/group- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/group- does not have a group owner of root? - - - - To verify that BIND uses the system crypto policy, check out that the BIND config file -/etc/named.conf contains the include "/etc/crypto-policies/back-ends/bind.config"; -directive: -$ sudo grep 'include "/etc/crypto-policies/back-ends/bind.config";' /etc/named.conf -Verify that the directive is at the bottom of the options section of the config file. - Is it the case that BIND is installed and the BIND config file doesn't contain the -<pre>include "/etc/crypto-policies/back-ends/bind.config";</pre> directive? - - - - The runtime status of the kernel.unprivileged_bpf_disabled -kernel parameter can be queried by running the following command: -$ sysctl kernel.unprivileged_bpf_disabled -The output of the command should indicate either: -kernel.unprivileged_bpf_disabled = 1 -or: -kernel.unprivileged_bpf_disabled = 2 -The output of the command should not indicate: -kernel.unprivileged_bpf_disabled = 0 - -The preferable way how to assure the runtime compliance is to have -correct persistent configuration, and rebooting the system. - -The persistent kernel parameter configuration is performed by specifying the appropriate -assignment in any file located in the /etc/sysctl.d directory. -Verify that there is not any existing incorrect configuration by executing the following command: -$ grep -r '^\s*\s*=' /etc/sysctl.conf /etc/sysctl.d -The command should not find any assignments other than: -kernel.unprivileged_bpf_disabled = 1 -or: -kernel.unprivileged_bpf_disabled = 2 - -Duplicate assignments are not allowed. Empty output is allowed, because the system default is 2. - Is it the case that the kernel.unprivileged_bpf_disabled is not set to 1 or 2 or is configured to be 0? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "newgrp" command with the following command: - -$ sudo auditctl -l | grep newgrp - --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -k privileged-newgrp - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the fs.protected_regular kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_regular -2. - - Is it the case that the correct value is not returned? - - - - - -Run the following command to determine the current status of the -auditd service: -$ sudo systemctl is-active auditd -If the service is running, it should return the following: active - Is it the case that the auditd service is not running? - - - - To check that the rsyncd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled rsyncd -Output should indicate the rsyncd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled rsyncd disabled - -Run the following command to verify rsyncd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active rsyncd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the rsyncd is masked, run the following command: -$ sudo systemctl show rsyncd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "rsyncd" is loaded and not masked? - - - - To check the ownership of /etc/ipsec.d, -run the command: -$ ls -lL /etc/ipsec.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ipsec.d does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_KEXEC /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine if the system is configured to audit calls to the -rmdir system call, run the following command: -$ sudo grep "rmdir" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -adjtimex system call, run the following command: -$ sudo grep "adjtimex" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine how the SSH daemon's IgnoreUserKnownHosts option is set, run the following command: - -$ sudo grep -i IgnoreUserKnownHosts /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check the ownership of /var/log, -run the command: -$ ls -lL /var/log -If properly configured, the output should indicate the following owner: -root - Is it the case that /var/log does not have an owner of root? - - - - # grep "^OPTIONS.*-u" /etc/sysconfig/chronyd | grep -v -e '-u\s*chrony\b' -returns no output - Is it the case that chronyd is not running under chrony user account? - - - - To determine how the SSH daemon's UsePAM option is set, run the following command: - -$ sudo grep -i UsePAM /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Run the following command to ensure postfix accepts mail messages from only the local system: -$ grep inet_interfaces /etc/postfix/main.cf -If properly configured, the output should show only . - Is it the case that it does not? - - - - To check the ownership of /etc/sestatus.conf, -run the command: -$ ls -lL /etc/sestatus.conf -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sestatus.conf does not have an owner of root? - - - - Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. - -Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: - -$ sudo grep disk_error_action /etc/audit/auditd.conf - -disk_error_action = HALT - -If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. - Is it the case that there is no evidence of appropriate action? - - - - Verify Oracle Linux 9 is securely comparing internal information system clocks at a regular interval with an NTP server with the following command: -$ sudo grep maxpoll /etc/ntp.conf /etc/chrony.conf /etc/chrony.d/ -server [ntp.server.name] iburst maxpoll . - Is it the case that "maxpoll" has not been set to the value of "<sub idref="var_time_service_set_maxpoll" />", is commented out, or is missing? - - - - Verify the noexec option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . noexec . . . - - Is it the case that the "/tmp" file system does not have the "noexec" option set? - - - - -Run the following command to determine if the ssh_sysadm_login SELinux boolean is disabled: -$ getsebool ssh_sysadm_login -If properly configured, the output should show the following: -ssh_sysadm_login --> off - Is it the case that ssh_sysadm_login is not disabled? - - - - To verify that auditing of privileged command use is configured, run the following command -to search privileged commands in relevant partitions and check if they are covered by auditd -rules: - -FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) -PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid" | awk '{ print $1 }') -for PARTITION in $PARTITIONS; do - for PRIV_CMD in $(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null); do - grep -qr "${PRIV_CMD}" /etc/audit/rules.d /etc/audit/audit.rules && - printf "OK: ${PRIV_CMD}\n" || printf "WARNING - rule not found for: ${PRIV_CMD}\n" - done -done - -The output should not contain any WARNING. - Is it the case that any setuid or setgid programs doesn't have a line in the audit rules? - - - - To check the group ownership of /boot/System.map*, -run the command: -$ ls -lL /boot/System.map* -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/System.map* does not have a group owner of root? - - - - To verify the noexec option is configured for all NFS mounts, run the following command: -$ mount | grep nfs -All NFS mounts should show the noexec setting in parentheses. This is not applicable if NFS is -not implemented. - Is it the case that the setting does not show? - - - - To check if MaxStartups is configured, run the following command: -$ sudo grep -r ^[\s]*MaxStartups /etc/ssh/sshd_config* -If configured, this command should output the configuration. - Is it the case that maxstartups is not configured? - - - - Run the following command and verify remote servers are configured properly: -# grep -E "^(server|pool)" /etc/chrony.conf - Is it the case that a remote time server is not configured? - - - - To check the group ownership of /etc/nftables, -run the command: -$ ls -lL /etc/nftables -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/nftables does not have a group owner of root? - - - - To check the group ownership of /etc/cron.daily, -run the command: -$ ls -lL /etc/cron.daily -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.daily does not have a group owner of root? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "unix_update" command with the following command: - -$ sudo auditctl -l | grep unix_update - --a always,exit -F path=/usr/bin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_update - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep -w space_left /etc/audit/auditd.conf - -space_left = % - Is it the case that the value of the "space_left" keyword is not set to <sub idref="var_auditd_space_left_percentage" />% of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. If the "space_left" value is not configured to the correct value? - - - - -If the system is configured to prevent the loading of the usb-storage kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the usb-storage kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To verify the number of rounds for the password hashing algorithm is configured, run the following command: -$ sudo grep rounds /etc/pam.d/password-auth -The output should show the following match: - -password sufficient pam_unix.so sha512 rounds= - Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +$ sudo cat /etc/audit/rules.d/11-loginuid.rules +The output has to be exactly as follows: +## Make the loginuid immutable. This prevents tampering with the auid. +--loginuid-immutable + Is it the case that the file does not exist or the content differs? @@ -257865,500 +278269,31 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - Verify the noexec option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . noexec . . . - - Is it the case that the "/var/log/audit" file system does not have the "noexec" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_ACPI_CUSTOM_METHOD /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine how the SSH daemon's PermitRootLogin option is set, run the following command: - -$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config - -If a line indicating prohibit-password is returned, then the required value is set. - Is it the case that it is commented out or not configured properly? - - - - Verify that the default umask for all local interactive users is "077". - -Identify the locations of all local interactive user home directories by looking at the "/etc/passwd" file. - -Check all local interactive user initialization files for interactive users with the following command: - -Note: The example is for a system that is configured to create users home directories in the "/home" directory. - -$ sudo find /home -maxdepth 2 -type f -name ".[^.]*" -exec grep -iH -d skip --exclude=.bash_history umask {} \; - -/home/wadea/.bash_history:grep -i umask /etc/bashrc /etc/csh.cshrc /etc/profile -/home/wadea/.bash_history:grep -i umask /etc/login.defs - Is it the case that any local interactive user initialization files are found to have a umask statement that sets a value less restrictive than "077"? - - - - Verify the noexec option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . noexec . . . - - Is it the case that the "/boot" file system does not have the "noexec" option set? - - - - Run the following command to determine if the sssd package is installed: $ rpm -q sssd - Is it the case that the package is not installed? - - - - Run the following command to determine the current status of the dnf-automatic timer: $ sudo systemctl is-active dnf-automatic.timer If the timer is running, it should return the following: active - Is it the case that the dnf-automatic.timer is not enabled? - - - - To check the permissions of /etc/crypttab, -run the command: -$ ls -l /etc/crypttab -If properly configured, the output should indicate the following permissions: -0600 - Is it the case that /etc/crypttab does not have unix mode 0600? - - - + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules +cat /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules The output has to be exactly as follows: -## Unsuccessful ownership change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +## Successful file modifications (open for write or truncate) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification Is it the case that the file does not exist or the content differs? - - Verify the assigned home directories of all interactive users on the system exist with the following command: - -$ sudo pwck -r - -user 'mailnull': directory 'var/spool/mqueue' does not exist - -The output should not return any interactive users. - Is it the case that users home directory does not exist? - - - - Verify the USBGuard has a policy configured with the following command: - -$ usbguard list-rules - -allow id 1d6b:0001 serial - -If the command does not return results or an error is returned, ask the SA to indicate how unauthorized peripherals are being blocked. - Is it the case that there is no evidence that unauthorized peripherals are being blocked before establishing a connection? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if compression is enabled or set correctly, run the -following command: -$ sudo grep Compression /etc/ssh/sshd_config -If configured properly, output should be no or delayed. - Is it the case that it is commented out, or is not set to no or delayed? - - - - Ensure there are no unconfined daemons running on the system, -the following command should produce no output: -$ sudo ps -eZ | grep "unconfined_service_t" - Is it the case that There are unconfined daemons running on the system? - - - - The following command will discover and print world-writable directories that -are not owned by root. Run it once for each local partition PART: -$ sudo find PART -xdev -type d -perm -0002 -uid +0 -print - Is it the case that there are world-writable directories not owned by root? - - - - If the system is not configured to audit time changes, this is a finding. -If the system is 64-bit only, this is not applicable -ocil: | -To determine if the system is configured to audit calls to the -stime system call, run the following command: -$ sudo grep "stime" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chcon" command with the following command: - -$ sudo auditctl -l | grep chcon - --a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that acquiring, saving, and processing core dumps is disabled, run the -following command: -$ systemctl status systemd-coredump.socket -The output should be similar to: -● systemd-coredump.socket - Loaded: masked (Reason: Unit systemd-coredump.socket is masked.) - Active: inactive (dead) ... - - Is it the case that unit systemd-coredump.socket is not masked or running? - - - - Verify the nosuid option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . nosuid . . . - - Is it the case that the "/home" file system does not have the "nosuid" option set? - - - - The group-owner of all log files written by rsyslog should be -root. -These log files are determined by the second part of each Rule line in -/etc/rsyslog.conf and typically all appear in /var/log. -To see the group-owner of a given log file, run the following command: -$ ls -l LOGFILE - Is it the case that the group-owner is not correct? - - - - To check the permissions of /etc/iptables, -run the command: -$ ls -l /etc/iptables -If properly configured, the output should indicate the following permissions: -0700 - Is it the case that /etc/iptables does not have unix mode 0700? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine if the system is configured to synchronize audit event data -with the log files on the disk: -$ sudo grep flush /etc/audit/auditd.conf -flush = DATA -Acceptable values are DATA, and SYNC. The setting is -case-insensitive. - Is it the case that auditd is not configured to synchronously write audit event data to disk? - - - - Verify the nosuid option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . nosuid . . . - - Is it the case that the "/var" file system does not have the "nosuid" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_SG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_WX /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine how the SSH daemon's PermitUserEnvironment option is set, run the following command: - -$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-3-access-success.rules +cat /etc/audit/rules.d/43-module-load.rules The output has to be exactly as follows: -## Successful file access (any other opens) This has to go last. -## These next two are likely to result in a whole lot of events --a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access --a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access +## These rules watch for kernel module insertion. By monitoring +## the syscall, we do not need any watches on programs. +-a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load +-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load +-a always,exit -F arch=b32 -S delete_module -F key=module-unload +-a always,exit -F arch=b64 -S delete_module -F key=module-unload Is it the case that the file does not exist or the content differs? - - - - Run the following command to check for duplicate group names: -Check that the operating system contains no duplicate Group ID (GID) for interactive users by running the following command: - - cut -d : -f 3 /etc/group | uniq -d - -If output is produced, this is a finding. -Configure the operating system to contain no duplicate GIDs. -Edit the file "/etc/group" and provide each group that has a duplicate GID with a unique GID. - Is it the case that the system has duplicate group ids? - - - - Run the following command to determine if the s-nail package is installed: $ rpm -q s-nail - Is it the case that the package is not installed? - - - - To check the ownership of /etc/issue.net, -run the command: -$ ls -lL /etc/issue.net -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/issue.net does not have an owner of root? - - - - Verify the operating system authenticates the remote logging server for off-loading audit logs with the following command: - -$ sudo grep -i '$ActionSendStreamDriverAuthMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should be -$/etc/rsyslog.conf:$ActionSendStreamDriverAuthMode x509/name - Is it the case that $ActionSendStreamDriverAuthMode in /etc/rsyslog.conf is not set to x509/name? - - - - To check the ownership of /etc/ipsec.secrets, -run the command: -$ ls -lL /etc/ipsec.secrets -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ipsec.secrets does not have an owner of root? - - - - The runtime status of the fs.protected_fifos kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_fifos -2. - - Is it the case that the correct value is not returned? - - - - Verify that a separate file system/partition has been created for /var with the following command: - -$ mountpoint /var - - Is it the case that "/var is not a mountpoint" is returned? - - - - To check the ownership of /etc/ipsec.conf, -run the command: -$ ls -lL /etc/ipsec.conf -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ipsec.conf does not have an owner of root? - - - - Verify the nosuid option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . nosuid . . . - - Is it the case that the "/var/log/audit" file system does not have the "nosuid" option set? - - - - To determine if NOPASSWD has been configured for sudo, run the following command: -$ sudo grep -ri nopasswd /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that nopasswd is specified in the sudo config files? - - - - Verify the nodev option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . nodev . . . - - Is it the case that the "/var/tmp" file system does not have the "nodev" option set? - - - - Verify that the shadow password suite configuration is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. - - -Check the hashing algorithm that is being used to hash passwords with the following command: - -$ sudo grep -i ENCRYPT_METHOD /etc/login.defs - -ENCRYPT_METHOD - Is it the case that ENCRYPT_METHOD is not set to <sub idref="var_password_hashing_algorithm" />? - - - - To check that the autofs service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled autofs -Output should indicate the autofs service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled autofs disabled - -Run the following command to verify autofs is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active autofs - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the autofs is masked, run the following command: -$ sudo systemctl show autofs | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "autofs" is loaded and not masked? - - - - To check the permissions of /etc/issue.net, -run the command: -$ ls -l /etc/issue.net -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/issue.net does not have unix mode -rw-r--r--? - - - - Verify that Oracle Linux 9 is configured to boot to the command line: -$ systemctl get-default -multi-user.target - Is it the case that the system default target is not set to "multi-user.target" and the Information System Security Officer (ISSO) lacks a documented requirement for a graphical user interface? - - - - To ensure the system is configured to ignore the Ctrl-Alt-Del setting, -enter the following command: -$ sudo grep -i ctrlaltdelburstaction /etc/systemd/system.conf -The output should return: -CtrlAltDelBurstAction=none - Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed more than 7 times in 2 seconds.? - - - - To ensure the X Windows package group is removed, run the following command: -$ rpm -qi xorg-x11-server-common -The output should be: -package xorg-x11-server-common is not installed - Is it the case that the X Windows package group or xorg-x11-server-common has not be removed? - - - - Verify the noexec option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . noexec . . . - - Is it the case that the "/var/log" file system does not have the "noexec" option set? - - - - To determine if the system is configured to audit calls to the -chmod system call, run the following command: -$ sudo grep "chmod" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -lsetxattr system call, run the following command: -$ sudo grep "lsetxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the openat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r openat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep openat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the permissions of /etc/sudoers, -run the command: -$ ls -l /etc/sudoers -If properly configured, the output should indicate the following permissions: -0440 - Is it the case that /etc/sudoers does not have unix mode 0440? - - - - To check the group ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? - - - - Verify Oracle Linux 9 security patches and updates are installed and up to date. -Updates are required to be applied with a frequency determined by organizational policy. - - - -Typical update frequency may be overridden by Information Assurance Vulnerability Alert (IAVA) notifications from CYBERCOM. - Is it the case that Oracle Linux 9 is in non-compliance with the organizational patching policy? @@ -258378,6 +278313,9 @@ The output has to be exactly as follows: ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -258481,46 +278419,855 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules +The output has to be exactly as follows: +## Unsuccessful ownership change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change + Is it the case that the file does not exist or the content differs? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules +The output has to be exactly as follows: +## Successful ownership change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change + Is it the case that the file does not exist or the content differs? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules +The output has to be exactly as follows: +## Unsuccessful permission change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change + Is it the case that the file does not exist or the content differs? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules +The output has to be exactly as follows: +## Successful permission change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change + Is it the case that the file does not exist or the content differs? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "init" command with the following command: -Run the following command to determine the current status of the -crond service: -$ sudo systemctl is-active crond -If the service is running, it should return the following: active +$ sudo auditctl -l | grep init + +-a always,exit -F path={{{ path }}}/init -F perm=x -F auid>=1000 -F auid!=unset -k privileged-init + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "poweroff" command with the following command: + +$ sudo auditctl -l | grep poweroff + +-a always,exit -F path={{{ path }}}/poweroff -F perm=x -F auid>=1000 -F auid!=unset -k privileged-poweroff + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "reboot" command with the following command: + +$ sudo auditctl -l | grep reboot + +-a always,exit -F path={{{ path }}}/reboot -F perm=x -F auid>=1000 -F auid!=unset -k privileged-reboot + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "shutdown" command with the following command: + +$ sudo auditctl -l | grep shutdown + +-a always,exit -F path={{{ path }}}/shutdown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-shutdown + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +chmod system call, run the following command: +$ sudo grep "chmod" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +chown system call, run the following command: +$ sudo grep "chown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchmod system call, run the following command: +$ sudo grep "fchmod" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchmodat system call, run the following command: +$ sudo grep "fchmodat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchown system call, run the following command: +$ sudo grep "fchown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchownat system call, run the following command: +$ sudo grep "fchownat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fremovexattr system call, run the following command: +$ sudo grep "fremovexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fsetxattr system call, run the following command: +$ sudo grep "fsetxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lchown system call, run the following command: +$ sudo grep "lchown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lremovexattr system call, run the following command: +$ sudo grep "lremovexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lsetxattr system call, run the following command: +$ sudo grep "lsetxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +removexattr system call, run the following command: +$ sudo grep "removexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +setxattr system call, run the following command: +$ sudo grep "setxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify that Oracle Linux 9 generates an audit record for all uses of the "umount" and system call. +To determine if the system is configured to audit calls to the +"umount" system call, run the following command: +$ sudo grep "umount" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line like the following. +-a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -k privileged-umount + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +umount2 system call, run the following command: +$ sudo grep "umount2" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/cron.d/" with the following command: + +$ sudo auditctl -l | grep /etc/cron.d/ + +-w /etc/cron.d/ -p wa -k cronjobs + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chacl" command with the following command: + +$ sudo auditctl -l | grep chacl + +-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chcon" command with the following command: + +$ sudo auditctl -l | grep chcon + +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "restorecon" command with the following command: + +$ sudo auditctl -l | grep restorecon + +-a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -k privileged-restorecon + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "semanage" command with the following command: + +$ sudo auditctl -l | grep semanage + +-a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setfacl" command with the following command: + +$ sudo auditctl -l | grep setfacl + +-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setfiles" command with the following command: + +$ sudo auditctl -l | grep setfiles + +-a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setsebool" command with the following command: + +$ sudo auditctl -l | grep setsebool + +-a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -k privileged + Is it the case that the command does not return a line, or the line is commented out? + + + + To verify that execution of the command is being audited, run the following command: +$ sudo grep "path=/usr/sbin/seunshare" /etc/audit/audit.rules /etc/audit/rules.d/* +The output should return something similar to: +-a always,exit -F path=/usr/sbin/seunshare -F auid>=1000 -F auid!=unset -F key=privileged Is it the case that ? - - The runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.secure_redirects -0. + + To determine if the system is configured to audit calls to the +rmdir system call, run the following command: +$ sudo grep "rmdir" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +unlink system call, run the following command: +$ sudo grep "unlink" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +unlinkat system call, run the following command: +$ sudo grep "unlinkat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +rename system call, run the following command: +$ sudo grep "rename" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +renameat system call, run the following command: +$ sudo grep "renameat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +renameat2 system call, run the following command: +$ sudo grep "renameat2" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +rename system call, run the following command: +$ sudo grep "rename" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. - Is it the case that the correct value is not returned? + Is it the case that no line is returned? - - To check the permissions of /etc/cron.d, -run the command: -$ ls -l /etc/cron.d -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.d does not have unix mode -rwx------? - - - - Run the following command to determine if the rsyslog package is installed: $ rpm -q rsyslog - Is it the case that the package is not installed? - - - - Verify the nodev option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . nodev . . . + + To determine if the system is configured to audit calls to the +renameat system call, run the following command: +$ sudo grep "renameat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. - Is it the case that the "/var" file system does not have the "nodev" option set? + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +rmdir system call, run the following command: +$ sudo grep "rmdir" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +unlink system call, run the following command: +$ sudo grep "unlink" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +unlinkat system call, run the following command: +$ sudo grep "unlinkat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify the audit system prevents unauthorized changes with the following command: + +$ sudo grep "^\s*[^#]" /etc/audit/audit.rules | tail -1 +-e 2 + + Is it the case that the audit system is not set to be immutable by adding the "-e 2" option to the end of "/etc/audit/audit.rules"? + + + + To determine if the system is configured to make login UIDs immutable, run +one of the following commands. +If the auditd daemon is configured to use the +augenrules program to read audit rules during daemon startup (the +default), run the following: +sudo grep immutable /etc/audit/rules.d/*.rules +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, run the following command: +sudo grep immutable /etc/audit/audit.rules +The following line should be returned: +--loginuid-immutable + Is it the case that the system is not configured to make login UIDs immutable? + + + + To determine if the system is configured to audit calls to the +init_module system call, run the following command: +$ sudo grep "init_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +finit_module system call, run the following command: +$ sudo grep "finit_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +delete_module system call, run the following command: +$ sudo grep "delete_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +delete_module system call, run the following command: +$ sudo grep "delete_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +finit_module system call, run the following command: +$ sudo grep "finit_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +init_module system call, run the following command: +$ sudo grep "init_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "" with the following command: + +$ sudo auditctl -l | grep + +-w -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/lastlog" with the following command: + +$ sudo auditctl -l | grep /var/log/lastlog + +-w /var/log/lastlog -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/tallylog" with the following command: + +$ sudo auditctl -l | grep /var/log/tallylog + +-w /var/log/tallylog -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit changes to its SELinux +configuration files, run the following command: +$ sudo auditctl -l | grep "dir=/etc/selinux" +If the system is configured to watch for changes to its SELinux +configuration, a line should be returned (including +perm=wa indicating permissions that are watched). + Is it the case that the system is not configured to audit attempts to change the MAC policy? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/selinux/" with the following command: + +$ sudo auditctl -l | grep /etc/selinux/ + +-w /etc/selinux/ -p wa -k MAC-policy + Is it the case that the system is not configured to audit attempts to change files within the /etc/selinux directory? + + + + To determine if the system is configured to audit changes to its SELinux +configuration files, run the following command: +$ sudo auditctl -l | grep "dir=/usr/share/selinux" +If the system is configured to watch for changes to its SELinux +configuration, a line should be returned (including +perm=wa indicating permissions that are watched). + Is it the case that the system is not configured to audit attempts to change the MAC policy? + + + + To determine if the system is configured to audit calls to the +mount system call, run the following command: +$ sudo grep "mount" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit changes to its network configuration, +run the following command: +auditctl -l | grep -E '(/etc/issue|/etc/issue.net|/etc/hosts|/etc/sysconfig/network)' + +If the system is configured to watch for network configuration changes, a line should be returned for +each file specified (and perm=wa should be indicated for each). + Is it the case that the system is not configured to audit changes of the network configuration? + + + + To verify that auditing of privileged command use is configured, run the following command +to search privileged commands in relevant partitions and check if they are covered by auditd +rules: + +FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) +PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid" | awk '{ print $1 }') +for PARTITION in $PARTITIONS; do + for PRIV_CMD in $(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null); do + grep -qr "${PRIV_CMD}" /etc/audit/rules.d /etc/audit/audit.rules && + printf "OK: ${PRIV_CMD}\n" || printf "WARNING - rule not found for: ${PRIV_CMD}\n" + done +done + +The output should not contain any WARNING. + Is it the case that any setuid or setgid programs doesn't have a line in the audit rules? + + + + To verify that auditing of privileged command use is configured, run the +following command: +$ sudo grep '\bat\b' /etc/audit/audit.rules /etc/audit/rules.d/* +It should return a relevant line in the audit rules. + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chage" command with the following command: + +$ sudo auditctl -l | grep chage + +-a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chage + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chsh" command with the following command: + +$ sudo auditctl -l | grep chsh + +-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chsh + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "crontab" command with the following command: + +$ sudo auditctl -l | grep crontab + +-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -k privileged-crontab + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "gpasswd" command with the following command: + +$ sudo auditctl -l | grep gpasswd + +-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-gpasswd + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "kmod" command with the following command: + +$ sudo auditctl -l | grep kmod + +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-kmod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "mount" command with the following command: + +$ sudo auditctl -l | grep mount + +-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-mount + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "newgrp" command with the following command: + +$ sudo auditctl -l | grep newgrp + +-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -k privileged-newgrp + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "pam_timestamp_check" command with the following command: + +$ sudo auditctl -l | grep pam_timestamp_check + +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pam_timestamp_check + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "passwd" command with the following command: + +$ sudo auditctl -l | grep passwd + +-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-passwd + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "postdrop" command with the following command: + +$ sudo auditctl -l | grep postdrop + +-a always,exit -F path=/usr/bin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postdrop + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "postqueue" command with the following command: + +$ sudo auditctl -l | grep postqueue + +-a always,exit -F path=/usr/bin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postqueue + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-agent" command with the following command: + +$ sudo auditctl -l | grep ssh-agent + +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-keysign" command with the following command: + +$ sudo auditctl -l | grep ssh-keysign + +-a always,exit -F path=/usr/libexec/openssh/ssh-keysignssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-keysign + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "su" command with the following command: + +$ sudo auditctl -l | grep su + +-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged-su + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "sudo" command with the following command: + +$ sudo auditctl -l | grep sudo + +-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudo + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "sudoedit" command with the following command: + +$ sudo auditctl -l | grep sudoedit + +-a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudoedit + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "umount" command with the following command: + +$ sudo auditctl -l | grep umount + +-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-umount + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "unix_chkpwd" command with the following command: + +$ sudo auditctl -l | grep unix_chkpwd + +-a always,exit -F path=/usr/bin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_chkpwd + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "unix_update" command with the following command: + +$ sudo auditctl -l | grep unix_update + +-a always,exit -F path=/usr/bin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "userhelper" command with the following command: + +$ sudo auditctl -l | grep userhelper + +-a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -k privileged-userhelper + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "usermod" command with the following command: + +$ sudo auditctl -l | grep usermod + +-a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-usermod + Is it the case that the command does not return a line, or the line is commented out? + + + + To verify that auditing of privileged command use is configured, run the +following command: +$ sudo grep usernetctl /etc/audit/audit.rules /etc/audit/rules.d/* +It should return a relevant line in the audit rules. + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/btmp" with the following command: + +$ sudo auditctl -l | grep /var/log/btmp + +-w /var/log/btmp -p wa -k session + Is it the case that Audit rule is not present? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/run/utmp" with the following command: + +$ sudo auditctl -l | grep /var/run/utmp + +-w /var/run/utmp -p wa -k session + Is it the case that Audit rule is not present? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/wtmp" with the following command: + +$ sudo auditctl -l | grep /var/log/wtmp + +-w /var/log/wtmp -p wa -k session + Is it the case that Audit rule is not present? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers + +-w /etc/sudoers -p wa -k actions + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers.d/" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers.d/ + +-w /etc/sudoers.d/ -p wa -k actions + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 audits the execution of privileged functions. + +Check if Oracle Linux 9 is configured to audit the execution of the "execve" system call using the following command: + +$ sudo grep execve /etc/audit/audit.rules + +The output should be the following: + + +-a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid +-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid +-a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid +-a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid + Is it the case that the command does not return all lines, or the lines are commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers + +-w /etc/sudoers -p wa -k actions + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers.d/" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers.d/ + +-w /etc/sudoers.d/ -p wa -k actions + Is it the case that there is not output? + + + + To verify that the system will shutdown when auditd fails, +run the following command: +$ sudo grep "\-f " /etc/audit/audit.rules +The output should contain: +-f + Is it the case that the system is not configured to shutdown on auditd failures? + + + + To determine if the system is configured to audit calls to the +adjtimex system call, run the following command: +$ sudo grep "adjtimex" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +clock_settime system call, run the following command: +$ sudo grep "clock_settime" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? @@ -258530,6 +279277,3639 @@ $ sudo grep "settimeofday" /etc/audit/audit.* If the system is configured to audit this activity, it will return a line. Is it the case that no line is returned? + + + + If the system is not configured to audit time changes, this is a finding. +If the system is 64-bit only, this is not applicable +ocil: | +To determine if the system is configured to audit calls to the +stime system call, run the following command: +$ sudo grep "stime" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/localtime" with the following command: + +$ sudo auditctl -l | grep /etc/localtime + +-w /etc/localtime -p wa -k audit_time_rules + Is it the case that the system is not configured to audit time changes? + + + + To verify that the audit system collects unauthorized file accesses, run the following commands: +$ sudo grep EACCES /etc/audit/audit.rules +$ sudo grep EPERM /etc/audit/audit.rules + Is it the case that 32-bit and 64-bit system calls to creat, open, openat, open_by_handle_at, truncate, and ftruncate are not audited during EACCES and EPERM? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the creat system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r creat /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep creat /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the ftruncate system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r ftruncate /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep ftruncate /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r open /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep open /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open_by_handle_at system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r open_by_handle_at /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep open_by_handle_at /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the openat system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r openat /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep openat /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the truncate system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r truncate /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep truncate /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit account changes, +run the following command: +auditctl -l | grep -E '(/etc/passwd|/etc/shadow|/etc/group|/etc/gshadow|/etc/security/opasswd)' +If the system is configured to watch for account changes, lines should be returned for +each file specified (and with perm=wa for each). + Is it the case that the system is not configured to audit account changes? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/group" with the following command: + +$ sudo auditctl -l | grep /etc/group + +-w /etc/group -p wa -k audit_rules_usergroup_modification + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/gshadow" with the following command: + +$ sudo auditctl -l | grep /etc/gshadow + +-w /etc/gshadow -p wa -k audit_rules_usergroup_modification + Is it the case that the system is not configured to audit account changes? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/security/opasswd" with the following command: + +$ sudo auditctl -l | grep /etc/security/opasswd + +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/passwd" with the following command: + +$ sudo auditctl -l | grep /etc/passwd + +-w /etc/passwd -p wa -k audit_rules_usergroup_modification + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/shadow" with the following command: + +$ sudo auditctl -l | grep /etc/shadow + +-w /etc/shadow -p wa -k audit_rules_usergroup_modification + Is it the case that command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/spool/cron" with the following command: + +$ sudo auditctl -l | grep /var/spool/cron + +-w /var/spool/cron -p wa -k cronjobs + Is it the case that command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/sudo.log" with the following command: + +$ sudo auditctl -l | grep /var/log/sudo.log + +-w /var/log/sudo.log -p wa -k maintenance + Is it the case that Audit rule is not present? + + + + To verify whether audispd plugin off-loads audit records onto a different +system or media from the system being audited, run the following command: + +$ sudo grep -i remote_server /etc/audit/audisp-remote.conf + +The output should return something similar to where REMOTE_SYSTEM +is an IP address or hostname: +remote_server = REMOTE_SYSTEM + +Determine which partition the audit records are being written to with the +following command: + +$ sudo grep log_file /etc/audit/auditd.conf +log_file = /var/log/audit/audit.log + +Check the size of the partition that audit records are written to with the +following command and verify whether it is sufficiently large: + +$ sudo df -h /var/log/audit/ +/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit + Is it the case that audispd is not sending logs to a remote system and the local partition has inadequate space? + + + + To verify the audispd's syslog plugin is active, run the following command: +$ sudo grep active /etc/audit/plugins.d/syslog.conf +If the plugin is active, the output will show yes. + Is it the case that it is not activated? + + + + Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. + +Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: + +$ sudo grep disk_error_action /etc/audit/auditd.conf + +disk_error_action = + +If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. + Is it the case that there is no evidence of appropriate action? + + + + Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. + +Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: + +$ sudo grep disk_error_action /etc/audit/auditd.conf + +disk_error_action = HALT + +If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. + Is it the case that there is no evidence of appropriate action? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + +Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + +$ sudo grep disk_full_action /etc/audit/auditd.conf + +disk_full_action = + +If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. + Is it the case that there is no evidence of appropriate action? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + +Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + +$ sudo grep disk_full_action /etc/audit/auditd.conf + +disk_full_action = + +If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. + Is it the case that there is no evidence of appropriate action? + + + + Verify that Oracle Linux 9 is configured to notify the SA and/or ISSO (at a minimum) in the event of an audit processing failure with the following command: + +$ sudo grep action_mail_acct /etc/audit/auditd.conf + +action_mail_acct = + Is it the case that the value of the "action_mail_acct" keyword is not set to "<sub idref="var_auditd_action_mail_acct" />" and/or other accounts for security personnel, the "action_mail_acct" keyword is missing, or the returned line is commented out, ask the system administrator to indicate how they and the ISSO are notified of an audit process failure. If there is no evidence of the proper personnel being notified of an audit processing failure? + + + + Verify that Oracle Linux 9 is configured to take action in the event of allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep admin_space_left_action /etc/audit/auditd.conf + +admin_space_left_action = single + +If the value of the "admin_space_left_action" is not set to "single", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. + Is it the case that there is no evidence that real-time alerts are configured on the system? + + + + Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w admin_space_left /etc/audit/auditd.conf + +admin_space_left = % + +If the value of the "admin_space_left" keyword is not set to % of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is taking action if the allocated storage is about to reach capacity. + Is it the case that the "admin_space_left" value is not configured to the correct value? + + + + Inspect /etc/audit/auditd.conf and locate the following line to +determine if the system is configured to synchronize audit event data +with the log files on the disk: +$ sudo grep flush /etc/audit/auditd.conf +flush = DATA +Acceptable values are DATA, and SYNC. The setting is +case-insensitive. + Is it the case that auditd is not configured to synchronously write audit event data to disk? + + + + Verify that the SA and ISSO (at a minimum) are notified when the audit storage volume is full. + +Check which action Oracle Linux 9 takes when the audit storage volume is full with the following command: + +$ sudo grep max_log_file_action /etc/audit/auditd.conf +max_log_file_action = + Is it the case that the value of the "max_log_file_action" option is set to "ignore", "rotate", or "suspend", or the line is commented out? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size. + +Check that Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size with the following command: + +$ sudo grep max_log_file_action /etc/audit/auditd.conf + +max_log_file_action = + Is it the case that the value of the "max_log_file_action" option is not "ROTATE", "SINGLE", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. If there is no evidence of appropriate action? + + + + Inspect /etc/audit/auditd.conf and locate the following line to +determine if the system is configured correctly: +space_left SIZE_in_MB + Is it the case that the system is not configured a specific size in MB to notify administrators of an issue? + + + + Verify Oracle Linux 9 notifies the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w space_left_action /etc/audit/auditd.conf + +space_left_action = + +If the value of the "space_left_action" is not set to "", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. + Is it the case that there is no evidence that real-time alerts are configured on the system? + + + + Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w space_left /etc/audit/auditd.conf + +space_left = % + Is it the case that the value of the "space_left" keyword is not set to <sub idref="var_auditd_space_left_percentage" />% of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. If the "space_left" value is not configured to the correct value? + + + + To verify that Audit Daemon is configured to flush to disk after +every records, run the following command: +$ sudo grep freq /etc/audit/auditd.conf +The output should return the following: +freq = + Is it the case that freq isn't set to <sub idref="var_auditd_freq" />? + + + + To verify that Audit Daemon is configured to include local events, run the +following command: +$ sudo grep local_events /etc/audit/auditd.conf +The output should return the following: +local_events = yes + Is it the case that local_events isn't set to yes? + + + + To verify that Audit Daemon is configured to resolve all uid, gid, syscall, +architecture, and socket address information before writing the event to disk, +run the following command: +$ sudo grep log_format /etc/audit/auditd.conf +The output should return the following: +log_format = ENRICHED + Is it the case that log_format isn't set to ENRICHED? + + + + To verify that Audit Daemon is configured to record the computer node +name in the audit events, run the following command: +$ sudo grep name_format /etc/audit/auditd.conf +The output should return the following: +name_format = + Is it the case that name_format isn't set to <sub idref="var_auditd_name_format" />? + + + + Verify the audit system is configured to take an appropriate action when the internal event queue is full: +$ sudo grep -i overflow_action /etc/audit/auditd.conf + +The output should contain overflow_action = syslog + +If the value of the "overflow_action" option is not set to syslog, +single, halt or the line is commented out, ask the System Administrator +to indicate how the audit logs are off-loaded to a different system or media. + Is it the case that auditd overflow action is not set correctly? + + + + To verify that Audit Daemon is configured to write logs to the disk, run the +following command: +$ sudo grep write_logs /etc/audit/auditd.conf +The output should return the following: +write_logs = yes + Is it the case that write_logs isn't set to yes? + + + + To check if the system login banner is compliant, +run the following command: + +$ cat /etc/issue + Is it the case that it does not display the required banner? + + + + To check if the system login banner is compliant, run the following command: +$ cat /etc/issue.net + Is it the case that it does not display the required banner? + + + + To check if the system motd banner is compliant, +run the following command: +$ cat /etc/motd + Is it the case that it does not display the required banner? + + + + Verify the NX (no-execution) bit flag is set on the system. + +Check that the no-execution bit flag is set with the following commands: + +$ sudo dmesg | grep NX + +[ 0.000000] NX (Execute Disable) protection: active + +If "dmesg" does not show "NX (Execute Disable) protection" active, check the cpuinfo settings with the following command: + +$ sudo grep flags /proc/cpuinfo +flags : fpu vme de pse tsc ms nx rdtscp lm constant_ts + +The output should contain the "nx" flag. + Is it the case that NX is disabled? + + + + Verify Oracle Linux 9 disables the chrony daemon from acting as a server with the following command: +$ grep -w port /etc/chrony.conf +port 0 + Is it the case that the "port" option is not set to "0", is commented out, or is missing? + + + + Run the following command and verify remote servers are configured properly: +# grep -E "^(server|pool)" /etc/chrony.conf + Is it the case that a remote time server is not configured? + + + + Verify Oracle Linux 9 disables network management of the chrony daemon with the following command: +$ grep -w cmdport /etc/chrony.conf +cmdport 0 + Is it the case that the "cmdport" option is not set to "0", is commented out, or is missing? + + + + Verify Oracle Linux 9 is securely comparing internal information system clocks at a regular interval with an NTP server with the following command: +$ sudo grep maxpoll /etc/ntp.conf /etc/chrony.conf /etc/chrony.d/ +server [ntp.server.name] iburst maxpoll . + Is it the case that "maxpoll" has not been set to the value of "<sub idref="var_time_service_set_maxpoll" />", is commented out, or is missing? + + + + # grep "^OPTIONS.*-u" /etc/sysconfig/chronyd | grep -v -e '-u\s*chrony\b' +returns no output + Is it the case that chronyd is not running under chrony user account? + + + + Run the following command and verify that time sources are only configured with server directive: +# grep -E "^(server|pool)" /etc/chrony.conf +A line with the appropriate server should be returned, any line returned starting with pool is a finding. + Is it the case that an authoritative remote time server is not configured or configured with pool directive? + + + + Run the following command and verify remote server is configured properly: +# grep -E "^(server|pool)" /etc/chrony.conf + Is it the case that a remote time server is not configured? + + + + Verify Oracle Linux 9 removes all software components after updated versions have been installed. + + +$ grep clean_requirements_on_remove /etc/yum.conf +clean_requirements_on_remove=1 + Is it the case that '"clean_requirements_on_remove" is not set to "1"'? + + + + To verify that BIND uses the system crypto policy, check out that the BIND config file +/etc/named.conf contains the include "/etc/crypto-policies/back-ends/bind.config"; +directive: +$ sudo grep 'include "/etc/crypto-policies/back-ends/bind.config";' /etc/named.conf +Verify that the directive is at the bottom of the options section of the config file. + Is it the case that BIND is installed and the BIND config file doesn't contain the +<pre>include "/etc/crypto-policies/back-ends/bind.config";</pre> directive? + + + + To verify that cryptography policy has been configured correctly, run the +following command: +$ update-crypto-policies --show +The output should return . +Run the command to check if the policy is correctly applied: +$ update-crypto-policies --is-applied +The output should be The configured policy is applied. +Moreover, check if settings for selected crypto policy are as expected. +List all libraries for which it holds that their crypto policies do not have symbolic link in /etc/crypto-policies/back-ends. +$ ls -l /etc/crypto-policies/back-ends/ | grep '^[^l]' | tail -n +2 | awk -F' ' '{print $NF}' | awk -F'.' '{print $1}' | sort +Subsequently, check if matching libraries have drop in files in the /etc/crypto-policies/local.d directory. +$ ls /etc/crypto-policies/local.d/ | awk -F'-' '{print $1}' | uniq | sort +Outputs of two previous commands should match. + Is it the case that cryptographic policy is not configured or is configured incorrectly? + + + + Inspect the list of enabled firewall ports and verify they are configured correctly by running +the following command: + +$ sudo firewall-cmd --list-all + +Ask the System Administrator for the site or program Ports, Protocols, and Services Management Component Local Service Assessment (PPSM CLSA). Verify the services allowed by the firewall match the PPSM CLSA. + Is it the case that there are additional ports, protocols, or services that are not in the PPSM CLSA, or there are ports, protocols, or services that are prohibited by the PPSM Category Assurance List (CAL), or there are no firewall rules configured? + + + + Check that the symlink exists and target the correct Kerberos crypto policy, with the following command: +file /etc/krb5.conf.d/crypto-policies +If command output shows the following line, Kerberos is configured to use the system-wide crypto policy. +/etc/krb5.conf.d/crypto-policies: symbolic link to /etc/crypto-policies/back-ends/krb5.config + Is it the case that the symlink does not exist or points to a different target? + + + + Verify that the IPSec service uses the system crypto policy. + +If the ipsec service is not installed is not applicable. + +Check to see if the "IPsec" service is active with the following command: + +$ systemctl status ipsec + +ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec +Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) +Active: inactive (dead) + +If the "IPsec" service is active, check to see if it is using the system crypto policy with the following command: + +$ sudo grep include /etc/ipsec.conf /etc/ipsec.d/*.conf + +/etc/ipsec.conf:include /etc/crypto-policies/back-ends/libreswan.config + Is it the case that the "IPsec" service is active and the ipsec configuration file does not contain does not contain <tt>include /etc/crypto-policies/back-ends/libreswan.config</tt>? + + + + Verify that Oracle Linux 9 loads the driver with the following command: + +$ grep card_drivers /etc/opensc.conf + +card_drivers = ; + Is it the case that "<sub idref="var_smartcard_drivers" />" is not listed as a card driver, or there is no line returned for "card_drivers"? + + + + To verify that OpenSSL uses the system crypto policy, check out that the OpenSSL config file +/etc/pki/tls/openssl.cnf contains the [ crypto_policy ] section with the +.include = /etc/crypto-policies/back-ends/opensslcnf.config directive: + +$ sudo grep '\.include\s* /etc/crypto-policies/back-ends/opensslcnf.config$' /etc/pki/tls/openssl.cnf. + Is it the case that the OpenSSL config file doesn't contain the whole section, +or the section doesn't contain the <pre>.include = /etc/crypto-policies/back-ends/opensslcnf.config</pre> directive? + + + + Verify that sshd isn't configured to ignore the system wide cryptographic policy. + +Check that the CRYPTO_POLICY variable is not set or is commented out in the +/etc/sysconfig/sshd. + +Run the following command: + +$ sudo grep CRYPTO_POLICY /etc/sysconfig/sshd + Is it the case that the CRYPTO_POLICY variable is set or is not commented out in the /etc/sysconfig/sshd? + + + + To verify that Linux Audit logging is enabled for the USBGuard daemon, +run the following command: +$ sudo grep AuditBackend /etc/usbguard/usbguard-daemon.conf +The output should be +AuditBackend=LinuxAudit + Is it the case that AuditBackend is not set to LinuxAudit? + + + + Verify that the system backups user data. + Is it the case that it is not? + + + + Verify "firewalld" is configured to employ a deny-all, allow-by-exception policy for allowing connections to other systems with the following commands: + +$ sudo firewall-cmd --state + +running + +$ sudo firewall-cmd --get-active-zones + +[custom] +interfaces: ens33 + +$ sudo firewall-cmd --info-zone=[custom] | grep target + +target: DROP + Is it the case that no zones are active on the interfaces or if the target is set to a different option other than "DROP"? + + + + Verify Oracle Linux 9 disables core dump backtraces by issuing the following command: + +$ grep -i process /etc/systemd/coredump.conf /etc/systemd/coredump.conf.d/*.conf + +ProcessSizeMax=0 + Is it the case that the "ProcessSizeMax" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + + + + Verify Oracle Linux 9 disables storing core dumps for all users by issuing the following command: + +$ grep -i storage /etc/systemd/coredump.conf /etc/systemd/coredump.conf.d/*.conf + +Storage=none + Is it the case that Storage is not set to none or is commented out and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + + + + In order to be sure that the databases are up-to-date, run the +dconf update +command as the administrator. + Is it the case that The system-wide dconf databases are up-to-date with regards to respective keyfiles? + + + + To ensure a login warning banner is enabled, run the following: +$ grep banner-message-enable /etc/dconf/db/local.d/* +If properly configured, the output should be true. +To ensure a login warning banner is locked and cannot be changed by a user, run the following: +$ grep banner-message-enable /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/banner-message-enable. + Is it the case that it is not? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling automount +If properly configured, the output for automount should be false. +To ensure that users cannot enable automount in GNOME3, run the following: +$ grep 'automount' /etc/dconf/db/local.d/locks/* +If properly configured, the output for automount should be /org/gnome/desktop/media-handling/automount + Is it the case that GNOME automounting is not disabled? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling automount-open +If properly configured, the output for automount-openshould be false. +To ensure that users cannot enable automount opening in GNOME3, run the following: +$ grep 'automount-open' /etc/dconf/db/local.d/locks/* +If properly configured, the output for automount-open should be /org/gnome/desktop/media-handling/automount-open + Is it the case that GNOME automounting is not disabled? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling autorun-never +If properly configured, the output for autorun-nevershould be true. +To ensure that users cannot enable autorun in GNOME3, run the following: +$ grep 'autorun-never' /etc/dconf/db/local.d/locks/* +If properly configured, the output for autorun-never should be /org/gnome/desktop/media-handling/autorun-never + Is it the case that GNOME autorun is not disabled? + + + + To ensure the system is configured to ignore the Ctrl-Alt-Del sequence, +run the following command: +$ gsettings get org.gnome.settings-daemon.plugins.media-keys logout +$ grep logout /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/settings-daemon/plugins/media-keys/logout + Is it the case that GNOME3 is configured to reboot when Ctrl-Alt-Del is pressed? + + + + To ensure disable and restart on the login screen are disabled, run the following command: +$ grep disable-restart-buttons /etc/dconf/db/local.d/* +The output should be true. +To ensure that users cannot enable disable and restart on the login screen, run the following: +$ grep disable-restart-buttons /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/disable-restart-buttons + Is it the case that disable-restart-buttons has not been configured or is not disabled? + + + + To ensure the user list is disabled, run the following command: +$ grep disable-user-list /etc/dconf/db/local.d/* +The output should be true. +To ensure that users cannot enable displaying the user list, run the following: +$ grep disable-user-list /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/disable-user-list + Is it the case that disable-user-list has not been configured or is not disabled? + + + + To ensure screen locking on smartcard removal is enabled, run the following command: +$ grep removal-action /etc/dconf/db/local.d/* +The output should be 'lock-screen'. +To ensure that users cannot disable screen locking on smartcard removal, run the following: +$ grep removal-action /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/settings-daemon/peripherals/smartcard/removal-action + Is it the case that removal-action has not been configured? + + + + +To ensure the login warning banner text is properly set, run the following: +$ grep banner-message-text /etc/dconf/db/local.d/* +If properly configured, the proper banner text will appear. +To ensure the login warning banner text is locked and cannot be changed by a user, run the following: +$ grep banner-message-text /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/banner-message-text. + Is it the case that it does not? + + + + To ensure that remote access requires credentials, run the following command: +$ gsettings get org.gnome.Vino authentication-methods +If properly configured, the output should be false. +To ensure that users cannot disable credentials for remote access, run the following: +$ grep authentication-methods /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/Vino/authentication-methods + Is it the case that wireless network notification is enabled and not disabled? + + + + To ensure that remote access connections are encrypted, run the following command: +$ gsettings get org.gnome.Vino require-encrpytion +If properly configured, the output should be true. +To ensure that users cannot disable encrypted remote connections, run the following: +$ grep require-encryption /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/Vino/require-encryption + Is it the case that remote access connections are not encrypted? + + + + To check the screensaver mandatory use status, run the following command: +$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled +If properly configured, the output should be true. +To ensure that users cannot disable the screensaver idle inactivity setting, run the following: +$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/screensaver/idle-activation-enabled + Is it the case that idle-activation-enabled is not enabled or configured? + + + + To check the current idle time-out value, run the following command: +$ gsettings get org.gnome.desktop.session idle-delay +If properly configured, the output should be 'uint32 '. +To ensure that users cannot change the screensaver inactivity timeout setting, run the following: +$ grep idle-delay /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/session/idle-delay + Is it the case that idle-delay is set to 0 or a value greater than <sub idref="inactivity_timeout_value" />? + + + + To check that the screen locks immediately when activated, run the following command: +$ gsettings get org.gnome.desktop.screensaver lock-delay +If properly configured, the output should be 'uint32 '. + Is it the case that the screensaver lock delay is missing, or is set to a value greater than <sub idref="var_screensaver_lock_delay" />? + + + + To check the status of the idle screen lock activation, run the following command: + +$ gsettings get org.gnome.desktop.screensaver lock-enabled +If properly configured, the output should be true. +To ensure that users cannot change how long until the screensaver locks, run the following: +$ grep lock-enabled /etc/dconf/db/local.d/locks/* +If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled + Is it the case that screensaver locking is not enabled and/or has not been set or configured correctly? + + + + To ensure the screensaver is configured to be blank, run the following command: +$ gsettings get org.gnome.desktop.screensaver picture-uri +If properly configured, the output should be ''. + +To ensure that users cannot set the screensaver background, run the following: +$ grep picture-uri /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/screensaver/picture-uri + Is it the case that it is not set or configured properly? + + + + To ensure that users cannot change session idle and lock settings, run the following: +$ grep 'lock-delay' /etc/dconf/db/local.d/locks/* +If properly configured, the output should return: +/org/gnome/desktop/screensaver/lock-delay + Is it the case that GNOME3 session settings are not locked or configured properly? + + + + To ensure that users cannot change session idle and lock settings, run the following: +$ grep 'idle-delay' /etc/dconf/db/local.d/locks/* +If properly configured, the output should return: +/org/gnome/desktop/session/idle-delay + Is it the case that idle-delay is not locked? + + + + Verify the system-wide shared library directories are group-owned by "root" with the following command: + +$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -group root -type d -exec stat -c "%n %G" '{}' \; + +If any system-wide shared library directory is returned and is not group-owned by a required system account, this is a finding. + Is it the case that any system-wide shared library directory is returned and is not group-owned by a required system account? + + + + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/local/bin +/usr/local/sbin +/usr/sbin +For each of these directories, run the following command to find files +not owned by root: +$ sudo find -L DIR/ ! -user root -type d -exec chown root {} \; + Is it the case that any system executables directories are found to not be owned by root? + + + + Verify the system-wide shared library directories are owned by "root" with the following command: + +$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -user root -type d -exec stat -c "%n %U" '{}' \; + Is it the case that any system-wide shared library directory is not owned by root? + + + + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +To find system executables directories that are group-writable or +world-writable, run the following command for each directory DIR +which contains system executables: +$ sudo find -L DIR -perm /022 -type d + Is it the case that any of these files are group-writable or world-writable? + + + + Shared libraries are stored in the following directories: +/lib +/lib64 +/usr/lib +/usr/lib64 + +To find shared libraries that are group-writable or world-writable, +run the following command for each directory DIR which contains shared libraries: +$ sudo find -L DIR -perm /022 -type d + Is it the case that any of these files are group-writable or world-writable? + + + + The following command will discover and print world-writable directories that +are not owned by root. Run it once for each local partition PART: +$ sudo find PART -xdev -type d -perm -0002 -uid +0 -print + Is it the case that there are world-writable directories not owned by root? + + + + To find world-writable directories that lack the sticky bit, run the following command: +$ sudo find / -type d \( -perm -0002 -a ! -perm -1000 \) -print 2>/dev/null +fixtext: |- +Configure all world-writable directories to have the sticky bit set to prevent unauthorized and unintended information transferred via shared system resources. + +Set the sticky bit on all world-writable directories using the command, replace "[World-Writable Directory]" with any directory path missing the sticky bit: + +$ chmod a+t [World-Writable Directory] +srg_requirement: +A sticky bit must be set on all Oracle Linux 9 public directories to prevent unauthorized and unintended information transferred via shared system resources. + Is it the case that any world-writable directories are missing the sticky bit? + + + + System commands are stored in the following directories: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +For each of these directories, run the following command to find directories not +owned by root: +$ sudo find -L $DIR ! -group root -type d -exec chgrp root {} \; + Is it the case that any of these directories are not group owned by root? + + + + System commands are stored in the following directories: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +For each of these directories, run the following command to find directories not +owned by root: +$ sudo find -L $DIR ! -user root -type d + Is it the case that any of these directories are not owned by root? + + + + To determine if the system is configured to audit accesses to +/var/log/audit directory, run the following command: +$ sudo grep "dir=/var/log/audit" /etc/audit/audit.rules +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + +Determine the audit log group by running the following command: + +$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf + +Then, check that all directories within the /var/log/audit directory are owned by the group specified as log_group or by root if the log_group is not specified. +Run the following command: + +$ sudo find /var/log/audit -type d -printf "%p %g\n" + +All listed directories must be owned by the log_group or by root if the log_group is not specified. + Is it the case that there is a directory owned by different group? + + + + To check the group ownership of /etc/ipsec.d, +run the command: +$ ls -lL /etc/ipsec.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ipsec.d does not have a group owner of +root +? + + + + To check the group ownership of /etc/iptables, +run the command: +$ ls -lL /etc/iptables +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/iptables does not have a group owner of +root +? + + + + To check the group ownership of /etc/nftables, +run the command: +$ ls -lL /etc/nftables +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/nftables does not have a group owner of +root +? + + + + To check the group ownership of /etc/selinux, +run the command: +$ ls -lL /etc/selinux +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/selinux does not have a group owner of +root +? + + + + To check the group ownership of /etc/sudoers.d, +run the command: +$ ls -lL /etc/sudoers.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sudoers.d does not have a group owner of +root +? + + + + To check the group ownership of /etc/sysctl.d, +run the command: +$ ls -lL /etc/sysctl.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sysctl.d does not have a group owner of +root +? + + + + To check the ownership of /etc/ipsec.d, +run the command: +$ ls -lL /etc/ipsec.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.d does not have an owner of root? + + + + To check the ownership of /etc/iptables, +run the command: +$ ls -lL /etc/iptables +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/iptables does not have an owner of root? + + + + To check the ownership of /etc/nftables, +run the command: +$ ls -lL /etc/nftables +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/nftables does not have an owner of root? + + + + To check the ownership of /etc/selinux, +run the command: +$ ls -lL /etc/selinux +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/selinux does not have an owner of root? + + + + To check the ownership of /etc/sudoers.d, +run the command: +$ ls -lL /etc/sudoers.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sudoers.d does not have an owner of root? + + + + To check the ownership of /etc/sysctl.d, +run the command: +$ ls -lL /etc/sysctl.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sysctl.d does not have an owner of root? + + + + Determine where the audit logs are stored with the following command: + +$ sudo grep -iw log_file /etc/audit/auditd.conf + +log_file = /var/log/audit/audit.log + +Determine the owner of the audit log directory by using the output of the above command +(default: "/var/log/audit/"). Run the following command with the correct audit log directory +path: + +$ sudo ls -ld /var/log/audit + +drwx------ 2 root root 23 Jun 11 11:56 /var/log/audit + +The audit log directory must be owned by "root" + Is it the case that the directory is not owned by root? + + + + To check the permissions of /etc/ipsec.d, +run the command: +$ ls -l /etc/ipsec.d +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/ipsec.d does not have unix mode 0700? + + + + To check the permissions of /etc/iptables, +run the command: +$ ls -l /etc/iptables +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/iptables does not have unix mode 0700? + + + + To check the permissions of /etc/nftables, +run the command: +$ ls -l /etc/nftables +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/nftables does not have unix mode 0700? + + + + To check the permissions of /etc/selinux, +run the command: +$ ls -l /etc/selinux +If properly configured, the output should indicate the following permissions: +0755 + Is it the case that /etc/selinux does not have unix mode 0755? + + + + To check the permissions of /etc/sudoers.d, +run the command: +$ ls -l /etc/sudoers.d +If properly configured, the output should indicate the following permissions: +0750 + Is it the case that /etc/sudoers.d does not have unix mode 0750? + + + + To check the permissions of /etc/sysctl.d, +run the command: +$ ls -l /etc/sysctl.d +If properly configured, the output should indicate the following permissions: +0755 + Is it the case that /etc/sysctl.d does not have unix mode 0755? + + + + Verify the audit log directories have a correct mode or less permissive mode. + +Find the location of the audit logs: + +$ sudo grep "^log_file" /etc/audit/auditd.conf + + +Find the group that owns audit logs: + +$ sudo grep "^log_group" /etc/audit/auditd.conf + + +Run the following command to check the mode of the system audit logs: + +$ sudo stat -c "%a %n" [audit_log_directory] + +Replace "[audit_log_directory]" to the correct audit log directory path, by default this location is "/var/log/audit". + + +If the log_group is "root" or is not set, the correct permissions are 0700, otherwise they are 0750. + Is it the case that audit logs have a more permissive mode? + + + + To ensure the system is configured to ignore the Ctrl-Alt-Del setting, +enter the following command: +$ sudo grep -i ctrlaltdelburstaction /etc/systemd/system.conf +The output should return: +CtrlAltDelBurstAction=none + Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed more than 7 times in 2 seconds.? + + + + To ensure the system is configured to mask the Ctrl-Alt-Del sequence, Check +that the ctrl-alt-del.target is masked and not active with the following +command: +sudo systemctl status ctrl-alt-del.target +The output should indicate that the target is masked and not active. It +might resemble following output: +ctrl-alt-del.target +Loaded: masked (/dev/null; bad) +Active: inactive (dead) + Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed? + + + + To determine how the SSH daemon's HostbasedAuthentication option is set, run the following command: + +$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Verify that core dumps are disabled for all users, run the following command: +$ grep core /etc/security/limits.conf +* hard core 0 + Is it the case that the "core" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core"? + + + + Verify the operating system is not configured to bypass password requirements for privilege +escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: +$ sudo grep pam_succeed_if /etc/pam.d/sudo + Is it the case that system is configured to bypass password requirements for privilege escalation? + + + + Verify users are provided with feedback on when account accesses last occurred with the following command: + +$ sudo grep pam_lastlog /etc/pam.d/postlogin + +session required pam_lastlog.so showfailed + Is it the case that "pam_lastlog.so" is not properly configured in "/etc/pam.d/postlogin" file? + + + + To verify that packages comprising the available updates will be automatically installed by dnf-automatic, run the following command: +$ sudo grep apply_updates /etc/dnf/automatic.conf +The output should return the following: +apply_updates = yes + Is it the case that apply_updates is not set to yes? + + + + To verify that only security updates will be automatically installed by dnf-automatic, run the following command: +$ sudo grep upgrade_type /etc/dnf/automatic.conf +The output should return the following: +upgrade_type = security + Is it the case that the upgrade_type is not set to security? + + + + Verify that authselect is enabled by running +authselect current +If authselect is enabled on the system, the output should show the ID of the profile which is currently in use. + Is it the case that authselect is not used to manage user authentication setup on the system? + + + + To verify that the DConf User profile is configured correctly, run the following +command: + +$ cat /etc/dconf/profile/user +The output should show the following: +user-db:user +system-db:local +system-db:site +system-db:distro + Is it the case that DConf User profile does not exist or is not configured correctly? + + + + To verify that the Dracut FIPS module is enabled, run the following command: +grep "add_dracutmodules" /etc/dracut.conf.d/40-fips.conf +The output should look like this: +add_dracutmodules+=" fips " + Is it the case that the Dracut FIPS module is not enabled? + + + + To verify that FIPS mode is enabled properly, run the following command: +cat /proc/sys/crypto/fips_enabled +The output be must: +1 + Is it the case that FIPS mode is not enabled? + + + + Check the system partitions to determine if they are encrypted with the following command: +blkid + +Output will be similar to: +/dev/sda1: UUID=" ab12c3de-4f56-789a-8f33-3850cc8ce3a2 +" TYPE="crypto_LUKS" +/dev/sda2: UUID=" bc98d7ef-6g54-321h-1d24-9870de2ge1a2 +" TYPE="crypto_LUKS" + +The boot partition and pseudo-file systems, such as /proc, /sys, and tmpfs, +are not required to use disk encryption and are not a finding. + Is it the case that partitions do not have a type of crypto_LUKS? + + + + To verify that EPEL repository is not enabled, run the following commands: +$ grep -r "^\[.*epel.*\]" /etc/yum.repos.d/ +For each EPEL repository found, check if it is enabled: +$ grep -A 5 "^\[.*epel.*\]" /etc/yum.repos.d/*.repo | grep "enabled" +The output should show enabled=0 for all EPEL repositories, or no EPEL repositories +should be present. + Is it the case that EPEL repository is enabled? + + + + Verify that yum verifies the signature of packages from a repository prior to install with the following command: + +$ grep gpgcheck /etc/yum.conf + +gpgcheck=1 + +If "gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. + Is it the case that there is no process to validate certificates that is approved by the organization? + + + + Verify that yum verifies the signature of local packages prior to install with the following command: + +$ grep localpkg_gpgcheck /etc/yum.conf + +localpkg_gpgcheck=1 + +If "localpkg_gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. + Is it the case that there is no process to validate certificates for local packages that is approved by the organization? + + + + To determine whether yum has been configured to disable +gpgcheck for any repos, inspect all files in +/etc/yum.repos.d and ensure the following does not appear in any +sections: +gpgcheck=0 +A value of 0 indicates that gpgcheck has been disabled for that repo. + Is it the case that GPG checking is disabled? + + + + To determine the status and frequency of logrotate, run the following command: +$ sudo grep logrotate /var/log/cron* +If logrotate is configured properly, output should include references to +/etc/cron.daily. + Is it the case that logrotate is not configured to run daily? + + + + To ensure that the GPG key is installed, run: +$ rpm -q --queryformat "%{SUMMARY}\n" gpg-pubkey +The command should return the string below: +gpg(Oracle OSS group (Open Source Software group) <build@oss.oracle.com> + Is it the case that the Oracle GPG Key is not installed? + + + + Run the following command to check if the group exists: +grep /etc/group +The output should contain the following line: +:x: + Is it the case that group exists and has no user members? + + + + root password is not set + Is it the case that Perform the following to determine if a password is set for the +root user: +<pre># grep -Eq '^root:\$[0-9]' /etc/shadow || echo "root is locked"</pre> +No results should be returned. +Otherwise, run the following command and follow the prompts to set a +password for the root user: +<pre># passwd root</pre>? + + + + To verify /etc/system-fips exists, run the following command: +ls -l /etc/system-fips +The output should be similar to the following: +-rw-r--r--. 1 root root 36 Nov 26 11:31 /etc/system-fips + Is it the case that /etc/system-fips does not exist? + + + + Verify the Oracle Linux 9 "fapolicyd" employs a deny-all, permit-by-exception policy. + +Check that "fapolicyd" is in enforcement mode with the following command: + +$ sudo grep permissive /etc/fapolicyd/fapolicyd.conf + +permissive = 0 + +Check that fapolicyd employs a deny-all policy on system mounts with the following commands: +$ sudo tail /etc/fapolicyd/compiled.rules + +allow exe=/usr/bin/python3.7 : ftype=text/x-python +deny_audit perm=any pattern=ld_so : all +deny perm=any all : all + Is it the case that fapolicyd is not running in enforcement mode with a deny-all, permit-by-exception policy? + + + + The file /etc/at.deny should not exist. +This can be checked by running the following + +stat /etc/at.deny + +and the output should be + +stat: cannot stat `/etc/at.deny': No such file or directory + + Is it the case that the file /etc/at.deny exists? + + + + Verify the audit tools are group-owned by "root" to prevent any unauthorized access, deletion, or modification. + +Check the group-owner of each audit tool by running the following command: + +$ sudo stat -c "%G %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + +root /sbin/auditctl +root /sbin/aureport +root /sbin/ausearch +root /sbin/autrace +root /sbin/auditd +root /sbin/rsyslogd +root /sbin/augenrules + Is it the case that any audit tools are not group-owned by root? + + + + Verify the audit tools are owned by "root" to prevent any unauthorized access, deletion, or modification. + +Check the owner of each audit tool by running the following command: + +$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + +root /sbin/auditctl +root /sbin/aureport +root /sbin/ausearch +root /sbin/autrace +root /sbin/auditd +root /sbin/rsyslogd +root /sbin/augenrules + Is it the case that any audit tools are not owned by root? + + + + Verify the audit tools are protected from unauthorized access, deletion, or modification by checking the permissive mode. + +Check the octal permission of each audit tool by running the following command: + +$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + Is it the case that any of these files have more permissive permissions than 0755? + + + + The file /etc/cron.deny should not exist. +This can be checked by running the following + +stat /etc/cron.deny + +and the output should be + +stat: cannot stat `/etc/cron.deny': No such file or directory + + Is it the case that the file /etc/cron.deny exists? + + + + Check group owners of the system audit logs. + +First, determine where the audit log file is located. + +$ sudo grep -iw ^log_file /etc/audit/auditd.conf +log_file = /var/log/audit/audit.log + +The log_file option specifies the audit log file path. +If the log_file option isn't defined, check all files within /var/log/audit directory. + + +Then, determine the audit log group by running the following command: +$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf + + +Then, check that the audit log file is owned by the correct group. +Run the following command to display the owner of the audit log file: + +$ sudo stat -c "%n %G" log_file + + +The audit log file must be owned by the log_group or by root if the log_group is not specified. + Is it the case that audit log files are owned by incorrect group? + + + + To check the group ownership of /etc/at.allow, +run the command: +$ ls -lL /etc/at.allow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/at.allow does not have a group owner of +root +? + + + + To check the group ownership of /etc/group-, +run the command: +$ ls -lL /etc/group- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/group- does not have a group owner of +root +? + + + + To check the group ownership of /etc/gshadow-, +run the command: +$ ls -lL /etc/gshadow- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/gshadow- does not have a group owner of +root +? + + + + To check the group ownership of /etc/passwd-, +run the command: +$ ls -lL /etc/passwd- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/passwd- does not have a group owner of +root +? + + + + To check the group ownership of /etc/shadow-, +run the command: +$ ls -lL /etc/shadow- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/shadow- does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.allow, +run the command: +$ ls -lL /etc/cron.allow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.allow does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.d, +run the command: +$ ls -lL /etc/cron.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.d does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.daily, +run the command: +$ ls -lL /etc/cron.daily +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.daily does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.deny, +run the command: +$ ls -lL /etc/cron.deny +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.deny does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.hourly, +run the command: +$ ls -lL /etc/cron.hourly +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.hourly does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.monthly, +run the command: +$ ls -lL /etc/cron.monthly +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.monthly does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.weekly, +run the command: +$ ls -lL /etc/cron.weekly +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.weekly does not have a group owner of +root +? + + + + To check the group ownership of /etc/crontab, +run the command: +$ ls -lL /etc/crontab +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/crontab does not have a group owner of +root +? + + + + To check the group ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/grub2/user.cfg does not have a group owner of +root +? + + + + To check the group ownership of /etc/chrony.keys, +run the command: +$ ls -lL /etc/chrony.keys +If properly configured, the output should indicate the following group-owner: + + chrony + + Is it the case that /etc/chrony.keys does not have a group owner of +chrony +? + + + + To check the group ownership of /etc/crypttab, +run the command: +$ ls -lL /etc/crypttab +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/crypttab does not have a group owner of +root +? + + + + To check the group ownership of /etc/group, +run the command: +$ ls -lL /etc/group +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/group does not have a group owner of +root +? + + + + To check the group ownership of /etc/gshadow, +run the command: +$ ls -lL /etc/gshadow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/gshadow does not have a group owner of +root +? + + + + To check the group ownership of /etc/ipsec.conf, +run the command: +$ ls -lL /etc/ipsec.conf +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ipsec.conf does not have a group owner of +root +? + + + + To check the group ownership of /etc/ipsec.secrets, +run the command: +$ ls -lL /etc/ipsec.secrets +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ipsec.secrets does not have a group owner of +root +? + + + + To check the group ownership of /etc/issue.net, +run the command: +$ ls -lL /etc/issue.net +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/issue.net does not have a group owner of +root +? + + + + To check the group ownership of /etc/passwd, +run the command: +$ ls -lL /etc/passwd +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/passwd does not have a group owner of +root +? + + + + To check the group ownership of /etc/sestatus.conf, +run the command: +$ ls -lL /etc/sestatus.conf +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sestatus.conf does not have a group owner of +root +? + + + + To check the group ownership of /etc/shadow, +run the command: +$ ls -lL /etc/shadow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/shadow does not have a group owner of +root +? + + + + To check the group ownership of /etc/shells, +run the command: +$ ls -lL /etc/shells +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/shells does not have a group owner of +root +? + + + + To check the group ownership of /etc/sudoers, +run the command: +$ ls -lL /etc/sudoers +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sudoers does not have a group owner of +root +? + + + + To check the group ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/grub2/grub.cfg does not have a group owner of +root +? + + + + To check the group ownership of /etc/ssh/sshd_config, +run the command: +$ ls -lL /etc/ssh/sshd_config +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ssh/sshd_config does not have a group owner of +root +? + + + + To check the group ownership of /boot/System.map*, +run the command: +$ ls -lL /boot/System.map* +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/System.map* does not have a group owner of +root +? + + + + To check the group ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/grub2/user.cfg does not have a group owner of +root +? + + + + To check the group ownership of /var/log, +run the command: +$ ls -lL /var/log +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /var/log does not have a group owner of +root +? + + + + To check the group ownership of /var/log/messages, +run the command: +$ ls -lL /var/log/messages +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /var/log/messages does not have a group owner of +root +? + + + + To check the group ownership of /var/log/syslog, +run the command: +$ ls -lL /var/log/syslog +If properly configured, the output should indicate the following group-owner: + + adm + + Is it the case that /var/log/syslog does not have a group owner of +adm +? + + + + +To properly set the group owner of /etc/audit/, run the command: + + $ sudo chgrp root /etc/audit/ + + + +To properly set the group owner of /etc/audit/rules.d/, run the command: + + $ sudo chgrp root /etc/audit/rules.d/ + + Is it the case that ? + + + + To verify the assigned home directory of all interactive users is group- +owned by that users primary GID, run the following command: +# ls -ld $(awk -F: '($3>=1000)&&($7 !~ /nologin/){print $6}' /etc/passwd) + Is it the case that the group ownership is incorrect? + + + + To check the group ownership of /etc/ssh/*_key, +run the command: +$ ls -lL /etc/ssh/*_key +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ssh/*_key does not have a group owner of +root +? + + + + To check the group ownership of /etc/ssh/*.pub, +run the command: +$ ls -lL /etc/ssh/*.pub +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ssh/*.pub does not have a group owner of +root +? + + + + Verify the system commands contained in the following directories are group-owned by "root", or a required system account, with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ! -group root -exec ls -l {} \; + Is it the case that any system commands are returned and is not group-owned by a required system account? + + + + To check the ownership of /etc/group-, +run the command: +$ ls -lL /etc/group- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/group- does not have an owner of root? + + + + To check the ownership of /etc/gshadow-, +run the command: +$ ls -lL /etc/gshadow- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/gshadow- does not have an owner of root? + + + + To check the ownership of /etc/passwd-, +run the command: +$ ls -lL /etc/passwd- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/passwd- does not have an owner of root? + + + + To check the ownership of /etc/shadow-, +run the command: +$ ls -lL /etc/shadow- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shadow- does not have an owner of root? + + + + To check the ownership of /etc/cron.allow, +run the command: +$ ls -lL /etc/cron.allow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.allow does not have an owner of root? + + + + To check the ownership of /etc/cron.d, +run the command: +$ ls -lL /etc/cron.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.d does not have an owner of root? + + + + To check the ownership of /etc/cron.daily, +run the command: +$ ls -lL /etc/cron.daily +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.daily does not have an owner of root? + + + + To check the ownership of /etc/cron.deny, +run the command: +$ ls -lL /etc/cron.deny +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.deny does not have an owner of root? + + + + To check the ownership of /etc/cron.hourly, +run the command: +$ ls -lL /etc/cron.hourly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.hourly does not have an owner of root? + + + + To check the ownership of /etc/cron.monthly, +run the command: +$ ls -lL /etc/cron.monthly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.monthly does not have an owner of root? + + + + To check the ownership of /etc/cron.weekly, +run the command: +$ ls -lL /etc/cron.weekly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.weekly does not have an owner of root? + + + + To check the ownership of /etc/crontab, +run the command: +$ ls -lL /etc/crontab +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/crontab does not have an owner of root? + + + + To check the ownership of /etc/chrony.keys, +run the command: +$ ls -lL /etc/chrony.keys +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/chrony.keys does not have an owner of root? + + + + To check the ownership of /etc/crypttab, +run the command: +$ ls -lL /etc/crypttab +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/crypttab does not have an owner of root? + + + + To check the ownership of /etc/group, +run the command: +$ ls -lL /etc/group +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/group does not have an owner of root? + + + + To check the ownership of /etc/gshadow, +run the command: +$ ls -lL /etc/gshadow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/gshadow does not have an owner of root? + + + + To check the ownership of /etc/ipsec.conf, +run the command: +$ ls -lL /etc/ipsec.conf +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.conf does not have an owner of root? + + + + To check the ownership of /etc/ipsec.secrets, +run the command: +$ ls -lL /etc/ipsec.secrets +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.secrets does not have an owner of root? + + + + To check the ownership of /etc/issue.net, +run the command: +$ ls -lL /etc/issue.net +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/issue.net does not have an owner of root? + + + + To check the ownership of /etc/passwd, +run the command: +$ ls -lL /etc/passwd +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/passwd does not have an owner of root? + + + + To check the ownership of /etc/sestatus.conf, +run the command: +$ ls -lL /etc/sestatus.conf +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sestatus.conf does not have an owner of root? + + + + To check the ownership of /etc/shadow, +run the command: +$ ls -lL /etc/shadow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shadow does not have an owner of root? + + + + To check the ownership of /etc/shells, +run the command: +$ ls -lL /etc/shells +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shells does not have an owner of root? + + + + To check the ownership of /etc/sudoers, +run the command: +$ ls -lL /etc/sudoers +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sudoers does not have an owner of root? + + + + To check the ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/grub.cfg does not have an owner of root? + + + + To check the ownership of /etc/ssh/sshd_config, +run the command: +$ ls -lL /etc/ssh/sshd_config +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/sshd_config does not have an owner of root? + + + + To check the ownership of /boot/System.map*, +run the command: +$ ls -lL /boot/System.map* +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/System.map* does not have an owner of root? + + + + To check the ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/user.cfg does not have an owner of root? + + + + To check the ownership of /var/log, +run the command: +$ ls -lL /var/log +If properly configured, the output should indicate the following owner: +root + Is it the case that /var/log does not have an owner of root? + + + + To check the ownership of /var/log/messages, +run the command: +$ ls -lL /var/log/messages +If properly configured, the output should indicate the following owner: +root + Is it the case that /var/log/messages does not have an owner of root? + + + + To check the ownership of /var/log/syslog, +run the command: +$ ls -lL /var/log/syslog +If properly configured, the output should indicate the following owner: +syslog + Is it the case that /var/log/syslog does not have an owner of syslog? + + + + +To properly set the owner of /etc/audit/, run the command: + + $ sudo chown root /etc/audit/ + + + +To properly set the owner of /etc/audit/rules.d/, run the command: + + $ sudo chown root /etc/audit/rules.d/ + + Is it the case that ? + + + + Verify the system commands contained in the following directories are owned by "root" with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin ! -user root -exec ls -l {} \; + Is it the case that any system commands are found to not be owned by root? + + + + Verify the system-wide shared library files are owned by "root" with the following command: + +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -user root -exec ls -l {} \; + Is it the case that any system wide shared library file is not owned by root? + + + + To check the ownership of /etc/ssh/*_key, +run the command: +$ ls -lL /etc/ssh/*_key +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/*_key does not have an owner of root? + + + + To check the ownership of /etc/ssh/*.pub, +run the command: +$ ls -lL /etc/ssh/*.pub +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/*.pub does not have an owner of root? + + + + +To properly set the owner of /var/log/audit, run the command: + + $ sudo chown root /var/log/audit + + + +To properly set the owner of /var/log/audit/*, run the command: + + $ sudo chown root /var/log/audit/* + + Is it the case that ? + + + + To verify that all user initialization files have a mode of 0740 or +less permissive, run the following command: +$ sudo find /home -type f -name '\.*' \( -perm -0002 -o -perm -0020 \) +There should be no output. + Is it the case that they are not 0740 or more permissive? + + + + To check the permissions of /etc/at.allow, +run the command: +$ ls -l /etc/at.allow +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/at.allow does not have unix mode -rw-r-----? + + + + +To properly set the permissions of /etc/audit/, run the command: +$ sudo chmod 0640 /etc/audit/ + +To properly set the permissions of /etc/audit/rules.d/, run the command: +$ sudo chmod 0640 /etc/audit/rules.d/ + Is it the case that ? + + + + To check the permissions of /etc/group-, +run the command: +$ ls -l /etc/group- +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/group- does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/gshadow-, +run the command: +$ ls -l /etc/gshadow- +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/gshadow- does not have unix mode ----------? + + + + To check the permissions of /etc/passwd-, +run the command: +$ ls -l /etc/passwd- +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/passwd- does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/shadow-, +run the command: +$ ls -l /etc/shadow- +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/shadow- does not have unix mode ----------? + + + + Verify the system commands contained in the following directories have mode "755" or less permissive with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin -perm /022 -exec ls -l {} \; + Is it the case that any system commands are found to be group-writable or world-writable? + + + + To check the permissions of /etc/cron.allow, +run the command: +$ ls -l /etc/cron.allow +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/cron.allow does not have unix mode -rw-r-----? + + + + To check the permissions of /etc/cron.d, +run the command: +$ ls -l /etc/cron.d +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.d does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.daily, +run the command: +$ ls -l /etc/cron.daily +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.daily does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.hourly, +run the command: +$ ls -l /etc/cron.hourly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.hourly does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.monthly, +run the command: +$ ls -l /etc/cron.monthly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.monthly does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.weekly, +run the command: +$ ls -l /etc/cron.weekly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.weekly does not have unix mode -rwx------? + + + + To check the permissions of /etc/crontab, +run the command: +$ ls -l /etc/crontab +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/crontab does not have unix mode -rw-------? + + + + To check the permissions of /etc/audit/auditd.conf, +run the command: +$ ls -l /etc/audit/auditd.conf +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/audit/auditd.conf does not have unix mode -rw-r-----? + + + + To check the permissions of /etc/audit/rules.d/*.rules, +run the command: +$ ls -l /etc/audit/rules.d/*.rules +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/audit/rules.d/*.rules does not have unix mode -rw-------? + + + + To check the permissions of /etc/chrony.keys, +run the command: +$ ls -l /etc/chrony.keys +If properly configured, the output should indicate the following permissions: +0640 + Is it the case that /etc/chrony.keys does not have unix mode 0640? + + + + To check the permissions of /etc/crypttab, +run the command: +$ ls -l /etc/crypttab +If properly configured, the output should indicate the following permissions: +0600 + Is it the case that /etc/crypttab does not have unix mode 0600? + + + + To check the permissions of /etc/group, +run the command: +$ ls -l /etc/group +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/group does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/gshadow, +run the command: +$ ls -l /etc/gshadow +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/gshadow does not have unix mode ----------? + + + + To check the permissions of /etc/ipsec.conf, +run the command: +$ ls -l /etc/ipsec.conf +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/ipsec.conf does not have unix mode 0644? + + + + To check the permissions of /etc/ipsec.secrets, +run the command: +$ ls -l /etc/ipsec.secrets +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/ipsec.secrets does not have unix mode 0644? + + + + To check the permissions of /etc/issue.net, +run the command: +$ ls -l /etc/issue.net +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/issue.net does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/passwd, +run the command: +$ ls -l /etc/passwd +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/passwd does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/sestatus.conf, +run the command: +$ ls -l /etc/sestatus.conf +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/sestatus.conf does not have unix mode 0644? + + + + To check the permissions of /etc/shadow, +run the command: +$ ls -l /etc/shadow +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/shadow does not have unix mode ----------? + + + + To check the permissions of /etc/shells, +run the command: +$ ls -l /etc/shells +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/shells does not have unix mode 0644? + + + + To check the permissions of /etc/sudoers, +run the command: +$ ls -l /etc/sudoers +If properly configured, the output should indicate the following permissions: +0440 + Is it the case that /etc/sudoers does not have unix mode 0440? + + + + To check the permissions of /boot/grub2/grub.cfg, run the command: +$ sudo ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following +permissions: -rw------- + Is it the case that it does not? + + + + To verify the assigned home directory of all interactive user home directories +have a mode of 0750 or less permissive, run the following command: +$ sudo ls -l /home +Inspect the output for any directories with incorrect permissions. + Is it the case that they are more permissive? + + + + To ensure the user home directory is not group-writable or world-readable, run the following: +# ls -ld /home/USER + Is it the case that the user home directory is group-writable or world-readable? + + + + Verify the system-wide shared library files contained in the following directories have mode "755" or less permissive with the following command: + +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 -perm /022 -type f -exec ls -l {} \; + Is it the case that any system-wide shared library file is found to be group-writable or world-writable? + + + + To check the permissions of /etc/ssh/sshd_config, +run the command: +$ ls -l /etc/ssh/sshd_config +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/ssh/sshd_config does not have unix mode -rw-------? + + + + To check the permissions of /etc/ssh/*_key, +run the command: +$ ls -l /etc/ssh/*_key +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/ssh/*_key does not have unix mode -rw-r-----? + + + + To check the permissions of /etc/ssh/*.pub, +run the command: +$ ls -l /etc/ssh/*.pub +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/ssh/*.pub does not have unix mode -rw-r--r--? + + + + To check the permissions of /boot/System.map*, +run the command: +$ ls -l /boot/System.map* +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/System.map* does not have unix mode -rw-------? + + + + To find SGID files, run the following command: +$ sudo find / -xdev -type f -perm -2000 + Is it the case that there is output? + + + + To find SUID files, run the following command: +$ sudo find / -xdev -type f -perm -4000 + Is it the case that only authorized files appear in the output of the find command? + + + + To find world-writable files, run the following command: +$ sudo find / -xdev -type f -perm -002 + Is it the case that there is output? + + + + The following command will locate the mount points related to local devices: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +The following command will show files which do not belong to a valid group: +$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null + +Replace MOUNTPOINT by the mount points listed by the fist command. + +No files without a valid group should be located. + Is it the case that there is output? + + + + To check the permissions of /boot/grub2/user.cfg, +run the command: +$ ls -l /boot/grub2/user.cfg +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? + + + + To check the permissions of /var/log, +run the command: +$ ls -l /var/log +If properly configured, the output should indicate the following permissions: +drwxr-xr-x + Is it the case that /var/log does not have unix mode drwxr-xr-x? + + + + Run the following command to check the mode of the system audit logs: +$ sudo grep -iw log_file /etc/audit/auditd.conf +log_file=/var/log/audit/audit.log +$ sudo stat -c "%n %a" /var/log/audit/* +$ sudo ls -l /var/log/audit +Audit logs must be mode 0640 or less permissive. + Is it the case that any permissions are more permissive? + + + + To check the permissions of /var/log/messages, +run the command: +$ ls -l /var/log/messages +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /var/log/messages does not have unix mode -rw-r-----? + + + + To check the permissions of /var/log/syslog, +run the command: +$ ls -l /var/log/syslog +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /var/log/syslog does not have unix mode -rw-r-----? + + + + Validate all files are symlinks to pointing to /usr/share/crypto-policies/FIPS/ except for +nss.config: + +$ stat -c%N /etc/crypto-policies/back-ends/* +'/etc/crypto-policies/back-ends/bind.config' -> '/usr/share/crypto-policies/FIPS/bind.txt' +'/etc/crypto-policies/back-ends/gnutls.config' -> '/usr/share/crypto-policies/FIPS/gnutls.txt' +'/etc/crypto-policies/back-ends/java.config' -> '/usr/share/crypto-policies/FIPS/java.txt' +'/etc/crypto-policies/back-ends/javasystem.config' -> '/usr/share/crypto-policies/FIPS/javasystem.txt' +'/etc/crypto-policies/back-ends/krb5.config' -> '/usr/share/crypto-policies/FIPS/krb5.txt' +'/etc/crypto-policies/back-ends/libreswan.config' -> '/usr/share/crypto-policies/FIPS/libreswan.txt' +'/etc/crypto-policies/back-ends/libssh.config' -> '/usr/share/crypto-policies/FIPS/libssh.txt' +'/etc/crypto-policies/back-ends/nss.config' +'/etc/crypto-policies/back-ends/openssh.config' -> '/usr/share/crypto-policies/FIPS/openssh.txt' +'/etc/crypto-policies/back-ends/opensshserver.config' -> '/usr/share/crypto-policies/FIPS/opensshserver.txt' +'/etc/crypto-policies/back-ends/opensslcnf.config' -> '/usr/share/crypto-policies/FIPS/opensslcnf.txt' +'/etc/crypto-policies/back-ends/openssl.config' -> '/usr/share/crypto-policies/FIPS/openssl.txt' +'/etc/crypto-policies/back-ends/openssl_fips.config' -> '/usr/share/crypto-policies/FIPS/openssl_fips.txt' + + Is it the case that Any file shows a different output? + + + + Verify "nftables" is configured to allow rate limits on any connection to the system with the following command: + +Verify "firewalld" has "nftables" set as the default backend: + +$ sudo grep -i firewallbackend /etc/firewalld/firewalld.conf + +# FirewallBackend +FirewallBackend=nftables + Is it the case that the "nftables" is not set as the "firewallbackend"? + + + + Inspect the firewalld trusted and default zones and verify the loopback traffic is restricted +to the lo interface by running the following command: + +$ sudo firewall-cmd --list-rich-rules --zone=trusted + +The following rich-rules should be listed: + +rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop +rule family="ipv6" source address="::1" destination not address="127.0.0.1" drop + + Is it the case that loopback traffic is not restricted? + + + + Inspect the network interfaces assigned to the firewalld trusted zone and verify the +lo interface is listed by running the following command: + +$ sudo firewall-cmd --list-interfaces --zone=trusted + Is it the case that loopback traffic is not trusted? + + + + + + +To determine if firewalld is configured to allow access + +on port 22/tcp, run the following command(s): + firewall-cmd --list-ports + + +to ssh + firewall-cmd --list-services + +If firewalld is configured to allow access through the firewall, something similar to the following will be output: + +If it is a service: +ssh + + +If it is a port: +22/tcp + + Is it the case that sshd service is not enabled in the proper firewalld zone? + + + + To ensure all GIDs referenced in /etc/passwd are defined in /etc/group, +run the following command: +$ sudo pwck -qr +There should be no output. + Is it the case that GIDs referenced in /etc/passwd are returned as not defined in /etc/group? + + + + To verify that automatic logins are disabled, run the following command: +$ grep -Pzoi "^\[daemon]\\nautomaticlogin.*" /etc/gdm/custom.conf +The output should show the following: +[daemon] +AutomaticLoginEnable=false + Is it the case that GDM allows users to automatically login? + + + + To ensure that XDMCP is disabled in /etc/gdm/custom.conf, run the following command: +grep -Pzo "\[xdmcp\]\nEnable=false" /etc/gdm/custom.conf +The output should return the following: + +[xdmcp] +Enable=false + + Is it the case that the Enable is not set to false or is missing in the xdmcp section of the /etc/gdm/custom.conf gdm configuration file? + + + + Run the following command to check for duplicate group names: +Check that the operating system contains no duplicate Group ID (GID) for interactive users by running the following command: + + cut -d : -f 3 /etc/group | uniq -d + +If output is produced, this is a finding. +Configure the operating system to contain no duplicate GIDs. +Edit the file "/etc/group" and provide each group that has a duplicate GID with a unique GID. + Is it the case that the system has duplicate group ids? + + + + To verify the boot loader superuser account has been set, run the following +command: +sudo grep -A1 "superusers" /boot/grub2/grub.cfg +The output should show the following: +set superusers="superusers-account" +export superusers +where superusers-account is the actual account name different from common names like root, +admin, or administrator and different from any other existing user name. + Is it the case that superuser account is not set or is set to root, admin, administrator or any other existing user name? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes audit=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*audit=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'audit=1' +The command should not return any output. + Is it the case that auditing is not enabled at boot time? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes audit_backlog_limit=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit_backlog_limit=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*audit_backlog_limit=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'audit_backlog_limit=' +The command should not return any output. + Is it the case that audit backlog limit is not configured? + + + + Inspect /etc/default/grub for any instances of +systemd.confirm_spawn=(1|yes|true|on) in the kernel boot arguments. +Presence of a systemd.confirm_spawn=(1|yes|true|on) indicates +that interactive boot is enabled at boot time and verify that +GRUB_DISABLE_RECOVERY=true to disable recovery boot. + Is it the case that Interactive boot is enabled at boot time? + + + + Verify that GRUB_DISABLE_RECOVERY is set to true in /etc/default/grub to disable recovery boot. +Run the following command: + +$ sudo grep GRUB_DISABLE_RECOVERY /etc/default/grub + Is it the case that GRUB_DISABLE_RECOVERY is not set to true or is missing? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes iommu=force, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*iommu=force.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*iommu=force.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'iommu=force' +The command should not return any output. + Is it the case that I/OMMU is not activated? + + + + Inspect /etc/default/grub for any instances of selinux=0 +in the kernel boot arguments. Presence of selinux=0 indicates +that SELinux is disabled at boot time. + Is it the case that SELinux is disabled at boot time? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes init_on_alloc=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*init_on_alloc=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*init_on_alloc=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'init_on_alloc=1' +The command should not return any output. + Is it the case that the kernel is not configured to zero out memory before allocation? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes l1tf=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*l1tf=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*l1tf=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'l1tf=' +The command should not return any output. + Is it the case that l1tf mitigations are not configured appropriately? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes mce=0, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mce=0.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*mce=0.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'mce=0' +The command should not return any output. + Is it the case that MCE tolerance is not set to zero? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes mds=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mds=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*mds=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'mds=' +The command should not return any output. + Is it the case that MDS mitigations are not configured appropriately? + + + + Make sure that the kernel is not disabling SMAP with the following +commands. +grep -q nosmap /boot/config-`uname -r` +If the command returns a line, it means that SMAP is being disabled. + Is it the case that the kernel is configured to disable SMAP? + + + + Make sure that the kernel is not disabling SMEP with the following +commands. +grep -q nosmep /boot/config-`uname -r` +If the command returns a line, it means that SMEP is being disabled. + Is it the case that the kernel is configured to disable SMEP? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes page_alloc.shuffle=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_alloc.shuffle=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*page_alloc.shuffle=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'page_alloc.shuffle=1' +The command should not return any output. + Is it the case that randomization of the page allocator is not enabled in the kernel? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes page_poison=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_poison=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*page_poison=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'page_poison=1' +The command should not return any output. + Is it the case that page allocator poisoning is not enabled? + + + + First, check whether the password is defined in either /boot/grub2/user.cfg or +/boot/grub2/grub.cfg. +Run the following commands: +$ sudo grep '^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$' /boot/grub2/user.cfg +$ sudo grep '^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$' /boot/grub2/grub.cfg + + +Second, check that a superuser is defined in /boot/grub2/grub.cfg. +$ sudo grep '^[\s]*set[\s]+superusers=("?)[a-zA-Z_]+\1$' /boot/grub2/grub.cfg + Is it the case that it does not produce any output? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes pti=on, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*pti=on.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*pti=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'pti=on' +The command should not return any output. + Is it the case that Kernel page-table isolation is not enabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes rng_core.default_quality=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*rng_core.default_quality=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*rng_core.default_quality=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'rng_core.default_quality=' +The command should not return any output. + Is it the case that trust on hardware random number generator is not configured appropriately? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes slab_nomerge=yes, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slab_nomerge=yes.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*slab_nomerge=yes.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'slab_nomerge=yes' +The command should not return any output. + Is it the case that merging of slabs with similar size is enabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes slub_debug=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slub_debug=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*slub_debug=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'slub_debug=' +The command should not return any output. + Is it the case that SLUB/SLAB poisoning is not enabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes spec_store_bypass_disable=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spec_store_bypass_disable=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*spec_store_bypass_disable=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'spec_store_bypass_disable=' +The command should not return any output. + Is it the case that SSB is not configured appropriately? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes spectre_v2=on, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spectre_v2=on.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*spectre_v2=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'spectre_v2=on' +The command should not return any output. + Is it the case that spectre_v2 mitigation is not enforced? + + + + Ensure that debug-shell service is not enabled with the following command: +grep systemd\.debug-shell=1 /boot/grub2/grubenv /etc/default/grub +If the command returns a line, it means that debug-shell service is being enabled. + Is it the case that the command returns a line? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes vsyscall=none, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*vsyscall=none.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*vsyscall=none.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'vsyscall=none' +The command should not return any output. + Is it the case that vsyscalls are enabled? + + + + To verify if the OpenSSH Client uses defined Crypto Policy, run: +$ cat /etc/ssh/ssh_config.d/02-ospp.conf +and verify that the line matches +Match final all +RekeyLimit 512M 1h +GSSAPIAuthentication no +Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc +PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 +MACs hmac-sha2-512,hmac-sha2-256 +KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1 + Is it the case that Crypto Policy for OpenSSH Client is not configured according to CC requirements? + + + + To verify if the OpenSSH client uses defined Cipher suite in the Crypto Policy, run: +$ grep -i ciphers /etc/crypto-policies/back-ends/openssh.config +and verify that the line matches: +Ciphers + Is it the case that Crypto Policy for OpenSSH client is not configured correctly? + + + + To verify if the OpenSSH server uses defined ciphers in the Crypto Policy, run: +$ grep -Po '(-oCiphers=\S+)' /etc/crypto-policies/back-ends/opensshserver.config +and verify that the line matches: +-oCiphers= + Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? + + + + To verify if the OpenSSH client uses defined MACs in the Crypto Policy, run: +$ grep -i macs /etc/crypto-policies/back-ends/openssh.config +and verify that the line matches: +MACs + Is it the case that Crypto Policy for OpenSSH client is not configured correctly? + + + + To verify if the OpenSSH server uses defined MACs in the Crypto Policy, run: +$ grep -Po '(-oMACs=\S+)' /etc/crypto-policies/back-ends/opensshserver.config +and verify that the line matches: +-oMACS= + Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? + + + + Check that Oracle Linux 9 has the packages for smart card support installed. + +Run the following command to determine if the openssl-pkcs11 package is installed: +$ rpm -q openssl-pkcs11 + Is it the case that smartcard software is not installed? + + + + To verify that the installed operating system is supported, run +the following command: + +$ grep -i "oracle" /etc/oracle-release + +Oracle Linux 9 + Is it the case that the installed operating system is not supported? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_ACPI_CUSTOM_METHOD /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_ARM64_SW_TTBR0_PAN /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BINFMT_MISC /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BUG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BUG_ON_DATA_CORRUPTION /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_COMPAT_BRK /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_COMPAT_VDSO /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_CREDENTIALS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_FS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_LIST /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_NOTIFIERS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_SG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_WX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: +$ grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config.* +For each kernel installed, a line with value should be returned. +If the system architecture is x86_64, the value should be 65536. +If the system architecture is aarch64, the value should be 32768. + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEVKMEM /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_FORTIFY_SOURCE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_LATENT_ENTROPY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_RANDSTRUCT /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STACKLEAK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HARDENED_USERCOPY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HARDENED_USERCOPY_FALLBACK /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HIBERNATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_IA32_EMULATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_IPV6 /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_KEXEC /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_PTYS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_EMULATE /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_NONE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_XONLY /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODIFY_LDT_SYSCALL /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_ALL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_FORCE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? @@ -258541,13 +282921,1405 @@ If the system is configured to audit this activity, it will return a line. Is it the case that the kernel was not built with the required value? - - The runtime status of the net.ipv4.conf.all.accept_local kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_local -0. + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_KEY /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_SHA512 /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING_ZERO /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_TABLE_ISOLATION /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PANIC_ON_OOPS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PANIC_TIMEOUT /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PROC_KCORE /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RANDOMIZE_BASE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RANDOMIZE_MEMORY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_REFCOUNT_FULL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RETPOLINE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SCHED_STACK_END_CHECK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECCOMP /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECCOMP_FILTER /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_YAMA /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_FREELIST_HARDENED /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_FREELIST_RANDOM /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_MERGE_DEFAULT /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLUB_DEBUG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STACKPROTECTOR /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STACKPROTECTOR_STRONG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STRICT_KERNEL_WRX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STRICT_MODULE_RWX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SYN_COOKIES /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_VMAP_STACK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_X86_VSYSCALL_EMULATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + +If the system is configured to prevent the loading of the atm kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - Is it the case that the correct value is not returned? +These lines can also instruct the module loading system to ignore the atm kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r atm /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the bluetooth kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the bluetooth kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r bluetooth /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the can kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the can kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r can /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the cramfs kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the cramfs kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r cramfs /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the dccp kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the dccp kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r dccp /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the firewire-core kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the firewire-core kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r firewire-core /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to disable the +ipv6 kernel module, it will contain a line +of the form: +options ipv6 disable=1 +Such lines may be inside any file in /etc/modprobe.d or the +deprecated/etc/modprobe.conf. This permits insertion of the IPv6 +kernel module (which other parts of the system expect to be present), but +otherwise keeps it inactive. Run the following command to search for such +lines in all files in /etc/modprobe.d and the deprecated +/etc/modprobe.conf: +$ grep -r ipv6 /etc/modprobe.conf /etc/modprobe.d + Is it the case that the ipv6 kernel module is not disabled? + + + + +If the system is configured to prevent the loading of the rds kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the rds kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r rds /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the sctp kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the sctp kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r sctp /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the tipc kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the tipc kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r tipc /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the usb-storage kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the usb-storage kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + If the device or Oracle Linux 9 does not have a camera installed, this requirement is not applicable. + +This requirement is not applicable to mobile devices (smartphones and tablets), where the use of the camera is a local AO decision. + +This requirement is not applicable to dedicated VTC suites located in approved VTC locations that are centrally managed. + +For an external camera, if there is not a method for the operator to manually disconnect the camera at the end of collaborative computing sessions, this is a finding. + +For a built-in camera, the camera must be protected by a camera cover (e.g., laptop camera cover slide) when not in use. If the built-in camera is not protected with a camera cover, or is not physically disabled, this is a finding. + +If the camera is not disconnected, covered, or physically disabled, determine if it is being disabled via software with the following commands: + +Verify the operating system disables the ability to load the uvcvideo kernel module. + +$ sudo grep -r uvcvideo /etc/modprobe.d/* | grep "/bin/true" + +install uvcvideo /bin/true + Is it the case that the command does not return any output, or the line is commented out, and the collaborative computing device has not been authorized for use? + + + + Verify that Oracle Linux 9 does not have unauthorized IP tunnels configured. + + +# yum list installed libreswan +libreswan.x86-64 3.20-5.el7_4 + + +If "libreswan" is installed, check to see if the "IPsec" service is active with the following command: + +# systemctl status ipsec +ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec +Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) +Active: inactive (dead) + + +If the "IPsec" service is active, check for configured IPsec connections (conn), perform the following: +grep -rni conn /etc/ipsec.conf /etc/ipsec.d/ +Verify any returned results for organizational approval. + Is it the case that the IPSec tunnels are not approved? + + + + Display the contents of the file /etc/systemd/logind.conf: +cat /etc/systemd/logind.conf +Ensure that there is a section [login] which contains the +configuration StopIdleSessionSec=. + Is it the case that the option is not configured? + + + + Verify the nosuid option is configured for the /boot/efi mount point, + run the following command: + $ sudo mount | grep '\s/boot/efi\s' + . . . /boot/efi . . . nosuid . . . + + Is it the case that the "/boot/efi" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . nodev . . . + + Is it the case that the "/boot" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . noexec . . . + + Is it the case that the "/boot" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . nosuid . . . + + Is it the case that the "/boot" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . nodev . . . + + Is it the case that the "/dev/shm" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . noexec . . . + + Is it the case that the "/dev/shm" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . nosuid . . . + + Is it the case that the "/dev/shm" file system does not have the "nosuid" option set? + + + + Verify the grpquota option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . grpquota . . . + + Is it the case that the "/home" file system does not have the "grpquota" option set? + + + + Verify the nodev option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . nodev . . . + + Is it the case that the "/home" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . noexec . . . + + Is it the case that the "/home" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . nosuid . . . + + Is it the case that the "/home" file system does not have the "nosuid" option set? + + + + Verify the usrquota option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . usrquota . . . + + Is it the case that the "/home" file system does not have the "usrquota" option set? + + + + To verify the sec option is configured for all NFS mounts, run the following command: +$ mount | grep "sec=" +All NFS mounts should show the sec=krb5:krb5i:krb5p setting in parentheses. +This is not applicable if NFS is not implemented. + Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? + + + + To verify the nodev option is configured for non-root local partitions, run the following command: +$ sudo mount | grep '^/dev\S* on /\S' | grep --invert-match 'nodev' +The output shows local non-root partitions mounted without the nodev option, and there should be no output at all. + + Is it the case that some mounts appear among output lines? + + + + To verify the nodev option is configured for all NFS mounts, run +the following command: +$ mount | grep nfs +All NFS mounts should show the nodev setting in parentheses. This +is not applicable if NFS is not implemented. + Is it the case that the setting does not show? + + + + Verify file systems that are used for removable media are mounted with the "nodev" option with the following command: + +$ sudo more /etc/fstab + +UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 + Is it the case that a file system found in "/etc/fstab" refers to removable media and it does not have the "nodev" option set? + + + + To verify the noexec option is configured for all NFS mounts, run the following command: +$ mount | grep nfs +All NFS mounts should show the noexec setting in parentheses. This is not applicable if NFS is +not implemented. + Is it the case that the setting does not show? + + + + To verify that binaries cannot be directly executed from removable media, run the following command: +$ grep -v noexec /etc/fstab +The resulting output will show partitions which do not have the noexec flag. Verify all partitions +in the output are not removable media. + Is it the case that removable media partitions are present? + + + + To verify the nosuid option is configured for all NFS mounts, run +the following command: +$ mount | grep nfs +All NFS mounts should show the nosuid setting in parentheses. This +is not applicable if NFS is not implemented. + Is it the case that the setting does not show? + + + + Verify file systems that are used for removable media are mounted with the "nosuid" option with the following command: + +$ sudo more /etc/fstab + +UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 + Is it the case that file system found in "/etc/fstab" refers to removable media and it does not have the "nosuid" option set? + + + + Verify the nosuid option is configured for the /opt mount point, + run the following command: + $ sudo mount | grep '\s/opt\s' + . . . /opt . . . nosuid . . . + + Is it the case that the "/opt" file system does not have the "nosuid" option set? + + + + Verify the nosuid option is configured for the /srv mount point, + run the following command: + $ sudo mount | grep '\s/srv\s' + . . . /srv . . . nosuid . . . + + Is it the case that the "/srv" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . nodev . . . + + Is it the case that the "/tmp" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . noexec . . . + + Is it the case that the "/tmp" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . nosuid . . . + + Is it the case that the "/tmp" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . nodev . . . + + Is it the case that the "/var/log/audit" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . noexec . . . + + Is it the case that the "/var/log/audit" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . nosuid . . . + + Is it the case that the "/var/log/audit" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . nodev . . . + + Is it the case that the "/var/log" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . noexec . . . + + Is it the case that the "/var/log" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . nosuid . . . + + Is it the case that the "/var/log" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . nodev . . . + + Is it the case that the "/var" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . noexec . . . + + Is it the case that the "/var" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . nosuid . . . + + Is it the case that the "/var" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . nodev . . . + + Is it the case that the "/var/tmp" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . noexec . . . + + Is it the case that the "/var/tmp" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . nosuid . . . + + Is it the case that the "/var/tmp" file system does not have the "nosuid" option set? + + + + Verify that DNS servers have been configured properly, perform the following: +$ sudo grep nameserver /etc/resolv.conf + Is it the case that less than two lines are returned that are not commented out? + + + + Using a non-privileged account, verify that users cannot modify or change +network settings with the nmcli command with the following command: +$ nmcli general permissions +The output should contain the following: +PERMISSION VALUE +org.freedesktop.NetworkManager.enable-disable-network auth +org.freedesktop.NetworkManager.enable-disable-wifi auth +org.freedesktop.NetworkManager.enable-disable-wwan auth +org.freedesktop.NetworkManager.enable-disable-wimax auth +org.freedesktop.NetworkManager.sleep-wake auth +org.freedesktop.NetworkManager.network-control auth +org.freedesktop.NetworkManager.wifi.share.protected auth +org.freedesktop.NetworkManager.wifi.share.open auth +org.freedesktop.NetworkManager.settings.modify.system auth +org.freedesktop.NetworkManager.settings.modify.own auth +org.freedesktop.NetworkManager.settings.modify.hostname auth +org.freedesktop.NetworkManager.settings.modify.global-dns auth +org.freedesktop.NetworkManager.reload auth +org.freedesktop.NetworkManager.checkpoint-rollback auth +org.freedesktop.NetworkManager.enable-disable-statistics auth +org.freedesktop.NetworkManager.enable-disable-connectivity-check auth +org.freedesktop.NetworkManager.wifi.scan auth + + Is it the case that non-privileged users can modify or change network settings? + + + + Verify that Promiscuous mode of an interface is disabled, run the following command: +$ ip link | grep PROMISC + Is it the case that any network device is in promiscuous mode? + + + + Verify that Oracle Linux 9 has a DNS mode configured in Network Manager. + +$ NetworkManager --print-config +[main] +dns= + Is it the case that the dns key under main does not exist or is not set to "none" or "default"? + + + + To verify all squashing has been disabled, run the following command: +$ grep all_squash /etc/exports + Is it the case that there is output? + + + + To ensure root may not directly login to the system over physical consoles, +run the following command: +cat /etc/securetty +If any output is returned, this is a finding. + Is it the case that the /etc/securetty file is not empty? + + + + To verify that null passwords cannot be used, run the following command: + +$ grep nullok /etc/pam.d/system-auth /etc/pam.d/password-auth + +If this produces any output, it may be possible to log into accounts +with empty passwords. Remove any instances of the nullok option to +prevent logins with empty passwords. + Is it the case that NULL passwords can be used? + + + + To verify that null passwords cannot be used, run the following command: +$ sudo awk -F: '!$2 {print $1}' /etc/shadow +If this produces any output, it may be possible to log into accounts +with empty passwords. + Is it the case that Blank or NULL passwords can be used? + + + + The following command will locate the mount points related to local devices: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +The following command will show files which do not belong to a valid user: +$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null + +Replace MOUNTPOINT by the mount points listed by the fist command. + +No files without a valid user should be located. + Is it the case that files exist that are not owned by a valid user? + + + + Verify that there are no shosts.equiv files on the system, run the following command: +$ find / -name shosts.equiv + Is it the case that shosts.equiv files exist? + + + + To check the system for the existence of any .netrc files, +run the following command: +$ sudo find /home -xdev -name .netrc + Is it the case that any .netrc files exist? + + + + To obtain a list of all users and the content of their shadow password field, run the command: +$ sudo readarray -t systemaccounts +Verify if all accounts are locked. + Is it the case that system accounts are not locked? + + + + The existence of the file /etc/hosts.equiv or a file named +.rhosts inside a user home directory indicates the presence +of an Rsh trust relationship. + Is it the case that these files exist? + + + + To obtain a listing of all users, their UIDs, and their shells, run the command: +$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd +Identify the system accounts from this listing. These will primarily be the accounts with UID +numbers less than 1000, other than root. + Is it the case that any system account other than root has a login shell? + + + + To verify that there are no .shosts files +on the system, run the following command: +$ sudo find / -name '.shosts' + Is it the case that .shosts files exist? + + + + Run the following command to determine if the aide package is installed: $ rpm -q aide + Is it the case that the package is not installed? + + + + Run the following command to determine if the audispd-plugins package is installed: $ rpm -q audispd-plugins + Is it the case that the package is not installed? + + + + Run the following command to determine if the audit package is installed: $ rpm -q audit + Is it the case that the audit package is not installed? + + + + Run the following command to determine if the bind package is installed: +$ rpm -q bind + Is it the case that the package is installed? + + + + Run the following command to determine if the chrony package is installed: $ rpm -q chrony + Is it the case that the package is not installed? + + + + Run the following command to determine if the cronie package is installed: +$ rpm -q cronie + Is it the case that the package is installed? + + + + Run the following command to determine if the crypto-policies package is installed: $ rpm -q crypto-policies + Is it the case that the package is not installed? + + + + Run the following command to determine if the cryptsetup package is installed: $ rpm -q cryptsetup + Is it the case that the package is not installed? + + + + Run the following command to determine if the cyrus-imapd package is installed: +$ rpm -q cyrus-imapd + Is it the case that the package is installed? + + + + Run the following command to determine if the dhcp-server package is installed: +$ rpm -q dhcp-server + Is it the case that the package is installed? + + + + Run the following command to determine if the dnf-automatic package is installed: $ rpm -q dnf-automatic + Is it the case that the package is not installed? + + + + Run the following command to determine if the dovecot package is installed: +$ rpm -q dovecot + Is it the case that the package is installed? + + + + Run the following command to determine if the fapolicyd package is installed: $ rpm -q fapolicyd + Is it the case that the fapolicyd package is not installed? + + + + Run the following command to determine if the firewalld package is installed: $ rpm -q firewalld + Is it the case that the package is not installed? + + + + The ftp package can be removed with the following command: $ sudo yum erase ftp + Is it the case that ? + + + + Run the following command to determine if the gnutls-utils package is installed: $ rpm -q gnutls-utils + Is it the case that the package is not installed? + + + + Run the following command to determine if the gssproxy package is installed: +$ rpm -q gssproxy + Is it the case that the package is installed? + + + + Run the following command to determine if the iprutils package is installed: +$ rpm -q iprutils + Is it the case that the package is installed? + + + + Run the following command to determine if the libreswan package is installed: $ rpm -q libreswan + Is it the case that the package is not installed? + + + + Run the following command to determine if the libselinux package is installed: $ rpm -q libselinux + Is it the case that the package is not installed? + + + + Run the following command to determine if the logrotate package is installed: $ rpm -q logrotate + Is it the case that the package is not installed? + + + + Run the following command to determine if the McAfeeTP package is installed: $ rpm -q McAfeeTP + Is it the case that the package is not installed? + + + + Run the following command to determine if the net-snmp package is installed: +$ rpm -q net-snmp + Is it the case that the package is installed? + + + + Run the following command to determine if the nfs-utils package is installed: +$ rpm -q nfs-utils + Is it the case that the package is installed? + + + + Run the following command to determine if the nftables package is installed: $ rpm -q nftables + Is it the case that the package is not installed? + + + + Run the following command to determine if the nss-tools package is installed: $ rpm -q nss-tools + Is it the case that the package is not installed? + + + + Run the following command to determine if the opensc package is installed: $ rpm -q opensc + Is it the case that the package is not installed? + + + + Run the following command to determine if the openscap-scanner package is installed: $ rpm -q openscap-scanner + Is it the case that the package is not installed? + + + + Run the following command to determine if the openssh-clients package is installed: $ rpm -q openssh-clients + Is it the case that the package is not installed? + + + + Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server + Is it the case that the package is not installed? + + + + Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server + Is it the case that the package is installed? + + + + Run the following command to determine if the pcsc-lite package is installed: $ rpm -q pcsc-lite + Is it the case that the package is not installed? + + + + Run the following command to determine if the policycoreutils-python-utils package is installed: $ rpm -q policycoreutils-python-utils + Is it the case that the package is not installed? + + + + Run the following command to determine if the policycoreutils package is installed: $ rpm -q policycoreutils + Is it the case that the policycoreutils package is not installed? + + + + Run the following command to determine if the postfix package is installed: $ rpm -q postfix + Is it the case that the package is not installed? + + + + Run the following command to determine if the quagga package is installed: +$ rpm -q quagga + Is it the case that the package is installed? + + + + Run the following command to determine if the rear package is installed: $ rpm -q rear + Is it the case that the package is not installed? + + + + Run the following command to determine if the rng-tools package is installed: $ rpm -q rng-tools + Is it the case that the package is not installed? + + + + Run the following command to determine if the rsyslog-gnutls package is installed: +$ rpm -q rsyslog-gnutls + Is it the case that the package is installed? + + + + Run the following command to determine if the rsyslog package is installed: $ rpm -q rsyslog + Is it the case that the package is not installed? + + + + Run the following command to determine if the s-nail package is installed: $ rpm -q s-nail + Is it the case that the package is not installed? + + + + Run the following command to determine if the scap-security-guide package is installed: $ rpm -q scap-security-guide + Is it the case that the package is not installed? + + + + Run the following command to determine if the sendmail package is installed: +$ rpm -q sendmail + Is it the case that the package is installed? + + + + Run the following command to determine if the setroubleshoot-plugins package is installed: +$ rpm -q setroubleshoot-plugins + Is it the case that the package is installed? + + + + Run the following command to determine if the setroubleshoot-server package is installed: +$ rpm -q setroubleshoot-server + Is it the case that the package is installed? + + + + Run the following command to determine if the squid package is installed: +$ rpm -q squid + Is it the case that the package is installed? + + + + Run the following command to determine if the sssd package is installed: $ rpm -q sssd + Is it the case that the package is not installed? + + + + Run the following command to determine if the sudo package is installed: $ rpm -q sudo + Is it the case that the package is not installed? + + + + Run the following command to determine if the syslog-ng-core package is installed: $ rpm -q syslog-ng-core + Is it the case that the package is not installed? + + + + Run the following command to determine if the telnet-server package is installed: +$ rpm -q telnet-server + Is it the case that the package is installed? + + + + The telnet package can be removed with the following command: $ sudo yum erase telnet + Is it the case that ? + + + + Run the following command to determine if the tftp-server package is installed: +$ rpm -q tftp-server + Is it the case that the package is installed? + + + + The tftp package can be removed with the following command: $ sudo yum erase tftp + Is it the case that ? + + + + Run the following command to determine if the tuned package is installed: +$ rpm -q tuned + Is it the case that the package is installed? + + + + Run the following command to determine if the usbguard package is installed: $ rpm -q usbguard + Is it the case that the package is not installed? + + + + Run the following command to determine if the vsftpd package is installed: +$ rpm -q vsftpd + Is it the case that the package is installed? + + + + To ensure the X Windows package group is removed, run the following command: +$ rpm -qi xorg-x11-server-common +The output should be: +package xorg-x11-server-common is not installed + Is it the case that the X Windows package group or xorg-x11-server-common has not be removed? + + + + Verify that a separate file system/partition has been created for /dev/shm with the following command: + +$ mountpoint /dev/shm + + Is it the case that "/dev/shm is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /home with the following command: + +$ mountpoint /home + + Is it the case that "/home is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /srv with the following command: + +$ mountpoint /srv + + Is it the case that "/srv is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /tmp with the following command: + +$ mountpoint /tmp + + Is it the case that "/tmp is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var with the following command: + +$ mountpoint /var + + Is it the case that "/var is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var/log with the following command: + +$ mountpoint /var/log + + Is it the case that "/var/log is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var/log/audit with the following command: + +$ mountpoint /var/log/audit + + Is it the case that "/var/log/audit is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var/tmp with the following command: + +$ mountpoint /var/tmp + + Is it the case that "/var/tmp is not a mountpoint" is returned? + + + + Find the list of alias maps used by the Postfix mail server: +$ sudo postconf alias_maps +Query the Postfix alias maps for an alias for the root user: +$ sudo postmap -q root hash:/etc/aliases +The output should return an alias. + Is it the case that the alias is not set? + + + + Find the list of alias maps used by the Postfix mail server: +$ sudo postconf alias_maps +Query the Postfix alias maps for an alias for the postmaster user: +$ sudo postmap -q postmaster hash:/etc/aliases +The output should return root. + Is it the case that the alias is not set or is not root? + + + + Run the following command to ensure postfix routes mail to this system: +$ grep relayhost /etc/postfix/main.cf +If properly configured, the output should show only . + Is it the case that it is not? + + + + Run the following command to ensure postfix accepts mail messages from only the local system: +$ grep inet_interfaces /etc/postfix/main.cf +If properly configured, the output should show only . + Is it the case that it does not? + + + + Verify that Oracle Linux 9 is configured to prevent unrestricted mail relaying, +run the following command: +$ sudo postconf -n smtpd_client_restrictions + Is it the case that the "smtpd_client_restrictions" parameter contains any entries other than "permit_mynetworks" and "reject"? + + + + To check if the installed Operating System is 64-bit, run the following command: +$ uname -m +The output should be one of the following: x86_64, aarch64, ppc64le or s390x. +If the output is i686 or i386 the operating system is 32-bit. +Check if the installed CPU supports 64-bit operating systems by running the following command: +$ lscpu | grep "CPU op-mode" +If the output contains 64bit, the CPU supports 64-bit operating systems. + Is it the case that the installed operating system is 32-bit but the CPU supports operation in 64-bit? + + + + To check if authentication is required for emergency mode, run the following command: +$ grep sulogin /usr/lib/systemd/system/emergency.service +The output should be similar to the following, and the line must begin with +ExecStart and /usr/lib/systemd/systemd-sulogin-shell. + ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + +Then, check if the emergency target requires the emergency service: +Run the following command: +$ sudo grep Requires /usr/lib/systemd/system/emergency.target +The output should be the following: +Requires=emergency.service + +Then, check if there is no custom emergency target configured in systemd configuration. +Run the following command: +$ sudo grep -r emergency.target /etc/systemd/system/ +The output should be empty. + +Then, check if there is no custom emergency service configured in systemd configuration. +Run the following command: +$ sudo grep -r emergency.service /etc/systemd/system/ +The output should be empty. + Is it the case that the output is different? @@ -258583,64 +284355,78 @@ There should be no output. Is it the case that the output is different? - - To ensure a login warning banner is enabled, run the following: -$ grep banner-message-enable /etc/dconf/db/local.d/* -If properly configured, the output should be true. -To ensure a login warning banner is locked and cannot be changed by a user, run the following: -$ grep banner-message-enable /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/banner-message-enable. - Is it the case that it is not? + + To check for serial port entries which permit root login, +run the following command: +$ sudo grep ^ttyS/[0-9] /etc/securetty +If any output is returned, then root login over serial ports is permitted. + Is it the case that root login over serial ports is permitted? - - Verify the value of the "maxclassrepeat" option in "/etc/security/pwquality.conf" with the following command: + + Verify the system-wide shared library files are group-owned by root with the following command: -$ grep maxclassrepeat /etc/security/pwquality.conf +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -group root -exec ls -l {} \; + Is it the case that any system wide shared library file is returned and is not group-owned by root? + + + + Verify that Oracle Linux 9 crypto-policies package has not been modified with the following command: +$ rpm -V crypto-policies +If the command has any output, this is a finding. + Is it the case that there is output? + + + + The following command will list which files on the system have file hashes different from what +is expected by the RPM database. +$ rpm -Va --noconfig | awk '$1 ~ /..5/' + Is it the case that there is output? + + + + The following command will list which files on the system have ownership different from what +is expected by the RPM database: +$ rpm -Va | rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' + Is it the case that there is output? + + + + The following command will list which files on the system have permissions different from what +is expected by the RPM database: +$ rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' + Is it the case that there is output? + + + + Verify that cron is logging to rsyslog, +run the following command: +grep -rni "cron\.\*" /etc/rsyslog.* +cron.* /var/log/cron +or +cron.* action(type="omfile" file="/var/log/cron") + Is it the case that cron is not logging to rsyslog? + + + + Verify the operating system authenticates the remote logging server for off-loading audit logs with the following command: -maxclassrepeat = - Is it the case that the value of "maxclassrepeat" is set to "0", more than "<sub idref="var_password_pam_maxclassrepeat" />" or is commented out? +$ sudo grep -i '$ActionSendStreamDriverAuthMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should be +$/etc/rsyslog.conf:$ActionSendStreamDriverAuthMode x509/name + Is it the case that $ActionSendStreamDriverAuthMode in /etc/rsyslog.conf is not set to x509/name? - - To verify the boot loader superuser password has been set, run the following command: -$ sudo grep "^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$" /boot/grub2/user.cfg -The output should be similar to: -GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.C4E08AC72FBFF7E837FD267BFAD7AEB3D42DDC -2C99F2A94DD5E2E75C2DC331B719FE55D9411745F82D1B6CFD9E927D61925F9BBDD1CFAA0080E0 -916F7AB46E0D.1302284FCCC52CD73BA3671C6C12C26FF50BA873293B24EE2A96EE3B57963E6D7 -0C83964B473EC8F93B07FE749AA6710269E904A9B08A6BBACB00A2D242AD828 - Is it the case that no password is set? - - - - To verify that rsyslog's Forwarding Output Module is configured -to use TLS for logging to remote server, run the following command: -$ grep omfwd /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should include record similar to -action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" - StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on") + + Verify the operating system encrypts audit records off-loaded onto a different system +or media from the system being audited with the following commands: -where the <remote system> present in the configuration line above must be a valid IP address or a host name of the remote logging server. - Is it the case that omfwd is not configured with gtls and AuthMode? - - - - The runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.accept_source_route -0. +$ sudo grep -i '$ActionSendStreamDriverMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/cron.weekly, -run the command: -$ ls -l /etc/cron.weekly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.weekly does not have unix mode -rwx------? +The output should be: + +/etc/rsyslog.conf:$ActionSendStreamDriverMode 1 + Is it the case that rsyslogd ActionSendStreamDriverMode is not set to 1? @@ -258655,457 +284441,14 @@ The output should be: Is it the case that rsyslogd DefaultNetstreamDriver not set to gtls? - - - -Run the following command to determine the current status of the -fapolicyd service: -$ sudo systemctl is-active fapolicyd -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - Run the following command to determine if the rsh-server package is installed: -$ rpm -q rsh-server - Is it the case that the package is installed? - - - - To determine if the system is configured to audit calls to the -fsetxattr system call, run the following command: -$ sudo grep "fsetxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_COMPAT_BRK /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLAB_FREELIST_RANDOM /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to determine if the sendmail package is installed: -$ rpm -q sendmail - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. - -Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: - -$ sudo grep disk_full_action /etc/audit/auditd.conf - -disk_full_action = - -If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. - Is it the case that there is no evidence of appropriate action? - - - - Verify the operating system requires re-authentication -when using the "sudo" command to elevate privileges, run the following command: -sudo grep -ri '^Defaults.*timestamp_timeout' /etc/sudoers /etc/sudoers.d -The output should be: -/etc/sudoers:Defaults timestamp_timeout=0 or "timestamp_timeout" is set to a positive number. -If conflicting results are returned, this is a finding. - Is it the case that timestamp_timeout is not set with the appropriate value for sudo? - - - - To ensure that remote access connections are encrypted, run the following command: -$ gsettings get org.gnome.Vino require-encrpytion -If properly configured, the output should be true. -To ensure that users cannot disable encrypted remote connections, run the following: -$ grep require-encryption /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/Vino/require-encryption - Is it the case that remote access connections are not encrypted? - - - - To check the group ownership of /etc/at.allow, -run the command: -$ ls -lL /etc/at.allow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/at.allow does not have a group owner of root? - - - - To determine how the SSH daemon's PermitEmptyPasswords option is set, run the following command: - -$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine if NOPASSWD or !authenticate have been configured for -sudo, run the following command: -$ sudo grep -ri "nopasswd\|\!authenticate" /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that nopasswd and/or !authenticate is enabled in sudo? - - - - To check the permissions of /etc/gshadow, -run the command: -$ ls -l /etc/gshadow -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/gshadow does not have unix mode ----------? - - - - To verify Certmap is enabled in SSSD, run the following command: -$ sudo cat /etc/sssd/sssd.conf -If configured properly, output should contain section like the following - -[certmap/testing.test/rule_name] -matchrule =<SAN>.*EDIPI@mil -maprule = (userCertificate;binary={cert!bin}) -domains = testing.test - - Is it the case that Certmap is not configured in SSSD? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HIBERNATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure disable and restart on the login screen are disabled, run the following command: -$ grep disable-restart-buttons /etc/dconf/db/local.d/* -The output should be true. -To ensure that users cannot enable disable and restart on the login screen, run the following: -$ grep disable-restart-buttons /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/disable-restart-buttons - Is it the case that disable-restart-buttons has not been configured or is not disabled? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes l1tf=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*l1tf=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*l1tf=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'l1tf=' -The command should not return any output. - Is it the case that l1tf mitigations are not configured appropriately? - - - - The runtime status of the net.ipv4.conf.default.send_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.send_redirects -0. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "crontab" command with the following command: - -$ sudo auditctl -l | grep crontab - --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -k privileged-crontab - Is it the case that the command does not return a line, or the line is commented out? - - - - To ensure sshd limits the users who can log in, run the following: -pre>$ sudo grep -rPi '^\h*(allow|deny)(users|groups)\h+\H+(\h+.*)?$' /etc/ssh/sshd_config* -If properly configured, the output should be a list of usernames and/or -groups allowed to log in to this system. - Is it the case that sshd does not limit the users who can log in? - - - - To find SGID files, run the following command: -$ sudo find / -xdev -type f -perm -2000 - Is it the case that there is output? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes page_alloc.shuffle=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_alloc.shuffle=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*page_alloc.shuffle=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'page_alloc.shuffle=1' -The command should not return any output. - Is it the case that randomization of the page allocator is not enabled in the kernel? - - - - To verify that the DConf User profile is configured correctly, run the following -command: - -$ cat /etc/dconf/profile/user -The output should show the following: -user-db:user -system-db:local -system-db:site -system-db:distro - Is it the case that DConf User profile does not exist or is not configured correctly? - - - - To check the screensaver mandatory use status, run the following command: -$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled -If properly configured, the output should be true. -To ensure that users cannot disable the screensaver idle inactivity setting, run the following: -$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/screensaver/idle-activation-enabled - Is it the case that idle-activation-enabled is not enabled or configured? - - - - Verify that authselect is enabled by running -authselect current -If authselect is enabled on the system, the output should show the ID of the profile which is currently in use. - Is it the case that authselect is not used to manage user authentication setup on the system? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_X86_VSYSCALL_EMULATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Promiscuous mode of an interface is disabled, run the following command: -$ ip link | grep PROMISC - Is it the case that any network device is in promiscuous mode? - - - - The file /etc/cron.deny should not exist. -This can be checked by runnig the following - -stat /etc/cron.deny - -and the output should be - -stat: cannot stat `/etc/cron.deny': No such file or directory - - Is it the case that the file /etc/cron.deny exists? - - - - Run the following command to determine if the nftables package is installed: $ rpm -q nftables - Is it the case that the package is not installed? - - - - To check the group ownership of /etc/cron.hourly, -run the command: -$ ls -lL /etc/cron.hourly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.hourly does not have a group owner of root? - - - - To check that the oddjobd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled oddjobd -Output should indicate the oddjobd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled oddjobd disabled - -Run the following command to verify oddjobd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active oddjobd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the oddjobd is masked, run the following command: -$ sudo systemctl show oddjobd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "oddjobd" is loaded and not masked? - - - - Verify that the interactive user account passwords last change time is not in the future -The following command should return no output -$ sudo expiration=$(cat /etc/shadow|awk -F ':' '{print $3}'); -for edate in ${expiration[@]}; do if [[ $edate > $(( $(date +%s)/86400 )) ]]; -then echo "Expiry date in future"; -fi; done - Is it the case that any interactive user password that has last change time in the future? - - - - Run the following command to determine if the tftp-server package is installed: -$ rpm -q tftp-server - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size. - -Check that Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size with the following command: - -$ sudo grep max_log_file_action /etc/audit/auditd.conf - -max_log_file_action = - Is it the case that the value of the "max_log_file_action" option is not "ROTATE", "SINGLE", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. If there is no evidence of appropriate action? - - - - Verify the system-wide shared library directories are group-owned by "root" with the following command: - -$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -group root -type d -exec stat -c "%n %G" '{}' \; - -If any system-wide shared library directory is returned and is not group-owned by a required system account, this is a finding. - Is it the case that any system-wide shared library directory is returned and is not group-owned by a required system account? - - - - Check that AIDE is properly configured to protect the integrity of the -audit tools by running the following command: - -# sudo cat /etc/aide.conf | grep /usr/sbin/au - -/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 - -/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 - - -If AIDE is configured properly to protect the integrity of the audit tools, -all lines listed above will be returned from the command. - -If one or more lines are missing, this is a finding. - Is it the case that integrity checks of the audit tools are missing or incomplete? - - - - To determine if the system is configured to audit calls to the -init_module system call, run the following command: -$ sudo grep "init_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -finit_module system call, run the following command: -$ sudo grep "finit_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -delete_module system call, run the following command: -$ sudo grep "delete_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - Verify "firewalld" is configured to employ a deny-all, allow-by-exception policy for allowing connections to other systems with the following commands: - -$ sudo firewall-cmd --state - -running - -$ sudo firewall-cmd --get-active-zones - -[custom] -interfaces: ens33 - -$ sudo firewall-cmd --info-zone=[custom] | grep target - -target: DROP - Is it the case that no zones are active on the interfaces or if the target is set to a different option other than "DROP"? - - - - Verify the audit tools are group-owned by "root" to prevent any unauthorized access, deletion, or modification. - -Check the group-owner of each audit tool by running the following command: - -$ sudo stat -c "%G %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - -root /sbin/auditctl -root /sbin/aureport -root /sbin/ausearch -root /sbin/autrace -root /sbin/auditd -root /sbin/rsyslogd -root /sbin/augenrules - Is it the case that any audit tools are not group-owned by root? - - - - To check the permissions of /etc/shells, -run the command: -$ ls -l /etc/shells -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/shells does not have unix mode 0644? - - - - To check the permissions of /etc/ssh/*.pub, -run the command: -$ ls -l /etc/ssh/*.pub -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/ssh/*.pub does not have unix mode -rw-r--r--? - - - - To ensure LoginGraceTime is set correctly, run the following command: -$ sudo grep LoginGraceTime /etc/ssh/sshd_config -If properly configured, the output should be: -LoginGraceTime -If the option is set to a number greater than 0, then the unauthenticated session will be disconnected -after the configured number seconds. - Is it the case that it is commented out or not configured properly? + + The group-owner of all log files written by rsyslog should be +root. +These log files are determined by the second part of each Rule line in +/etc/rsyslog.conf and typically all appear in /var/log. +To see the group-owner of a given log file, run the following command: +$ ls -l LOGFILE + Is it the case that the group-owner is not correct? @@ -259120,1134 +284463,15 @@ $ ls -l LOGFILE Is it the case that the owner is not correct? - - - -Run the following command to determine the current status of the -postfix service: -$ sudo systemctl is-active postfix -If the service is running, it should return the following: active - Is it the case that the system is not a cross domain solution and the service is not enabled? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: - -$ sudo auditctl -l | grep - --w -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that the installed operating system is supported, run -the following command: - -$ grep -i "oracle" /etc/oracle-release - -Oracle Linux 9 - Is it the case that the installed operating system is not supported? - - - - To ensure the user home directory is not group-writable or world-readable, run the following: -# ls -ld /home/USER - Is it the case that the user home directory is group-writable or world-readable? - - - - To check the permissions of /etc/sysctl.d, -run the command: -$ ls -l /etc/sysctl.d -If properly configured, the output should indicate the following permissions: -0755 - Is it the case that /etc/sysctl.d does not have unix mode 0755? - - - - To check the ownership of /etc/ssh/sshd_config, -run the command: -$ ls -lL /etc/ssh/sshd_config -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/sshd_config does not have an owner of root? - - - - To check the permissions of /boot/grub2/grub.cfg, run the command: -$ sudo ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following -permissions: -rwx------ - Is it the case that it does not? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "shutdown" command with the following command: - -$ sudo auditctl -l | grep shutdown - --a always,exit -F path=/shutdown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-shutdown - Is it the case that the command does not return a line, or the line is commented out? - - - - - -Run the following command to determine the current status of the -firewalld service: -$ sudo systemctl is-active firewalld -If the service is running, it should return the following: active - Is it the case that the "firewalld" service is disabled, masked, or not started.? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chacl" command with the following command: - -$ sudo auditctl -l | grep chacl - --a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the quagga package is installed: -$ rpm -q quagga - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 disables the chrony daemon from acting as a server with the following command: -$ grep -w port /etc/chrony.conf -port 0 - Is it the case that the "port" option is not set to "0", is commented out, or is missing? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-agent" command with the following command: - -$ sudo auditctl -l | grep ssh-agent - --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent - Is it the case that the command does not return a line, or the line is commented out? - - - - Check to see if Online Certificate Status Protocol (OCSP) -is enabled and using the proper digest value on the system with the following command: -$ sudo grep certificate_verification /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf | grep -v "^#" -If configured properly, output should look like - - certificate_verification = ocsp_dgst= - - Is it the case that certificate_verification in sssd is not configured? - - - - To check the group ownership of /etc/sestatus.conf, -run the command: -$ ls -lL /etc/sestatus.conf -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sestatus.conf does not have a group owner of root? - - - - Run the following command to determine if the talk package is installed: -$ rpm -q talk - Is it the case that the package is installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_FORTIFY_SOURCE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLAB_MERGE_DEFAULT /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if RekeyLimit is set correctly, run the -following command: - -$ sudo grep RekeyLimit /etc/ssh/sshd_config - -If configured properly, output should be -RekeyLimit - Is it the case that it is commented out or is not set? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open_by_handle_at system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r open_by_handle_at /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep open_by_handle_at /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the permissions of /etc/cron.hourly, -run the command: -$ ls -l /etc/cron.hourly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.hourly does not have unix mode -rwx------? - - - - Verify the pam_faillock.so module is present in the "/etc/pam.d/password-auth" file: - -$ sudo grep pam_faillock.so /etc/pam.d/password-auth - -auth required pam_faillock.so preauth -auth required pam_faillock.so authfail -account required pam_faillock.so - Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/password-auth" file with the "preauth" line listed before pam_unix.so? - - - - To verify that Audit Daemon is configured to flush to disk after -every records, run the following command: -$ sudo grep freq /etc/audit/auditd.conf -The output should return the following: -freq = - Is it the case that freq isn't set to <sub idref="var_auditd_freq" />? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_ALL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_pinfo -0. - - Is it the case that the correct value is not returned? - - - - Run the following command to determine if the openssh-clients package is installed: $ rpm -q openssh-clients - Is it the case that the package is not installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify the LDAP client backend demands a valid certificate from the server in -remote LDAP access sessions, run the following command: -$ sudo grep ldap_tls_reqcert /etc/sssd/sssd.conf -The output should return the following: -ldap_tls_reqcert = demand - Is it the case that the TLS reqcert is not set to demand? - - - - Verify Oracle Linux 9 prevents the use of dictionary words for passwords with the following command: - -$ sudo grep dictcheck /etc/security/pwquality.conf /etc/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:dictcheck=1 - Is it the case that "dictcheck" does not have a value other than "0", or is commented out? - - - - To check the ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/user.cfg does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SCHED_STACK_END_CHECK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to determine if the logrotate package is installed: $ rpm -q logrotate - Is it the case that the package is not installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure that users cannot change session idle and lock settings, run the following: -$ grep 'idle-delay' /etc/dconf/db/local.d/locks/* -If properly configured, the output should return: -/org/gnome/desktop/session/idle-delay - Is it the case that idle-delay is not locked? - - - - To check the permissions of /etc/shadow-, -run the command: -$ ls -l /etc/shadow- -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/shadow- does not have unix mode ----------? - - - - Inspect the firewalld trusted and default zones and verify the loopback traffic is restricted -to the lo interface by running the following command: - -$ sudo firewall-cmd --list-rich-rules --zone=trusted - -The following rich-rules should be listed: - -rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop -rule family="ipv6" source address="::1" destination not address="127.0.0.1" drop - - Is it the case that loopback traffic is not restricted? - - - - -Run the following command to get the current configured value for polyinstantiation_enabled -SELinux boolean: -$ getsebool polyinstantiation_enabled -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that polyinstantiation_enabled is not set as expected? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_KEY /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To find the location of the AIDE database file, run the following command: -$ sudo ls -l DBDIR/database_file_name - Is it the case that there is no database file? - - - - To check the group ownership of /etc/sudoers.d, -run the command: -$ ls -lL /etc/sudoers.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sudoers.d does not have a group owner of root? - - - - Run the following command to determine if the vsftpd package is installed: -$ rpm -q vsftpd - Is it the case that the package is installed? - - - - To verify the inactive setting, run the following command: -$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth -The output should indicate the inactive configuration option is set -to an appropriate integer between 1 and -; and should appear -before the pam_unix.so module as shown in the example below: -$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth -auth required pam_lastlog.so inactive= -auth sufficient pam_unix.so - Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? - - - - To verify the inactive setting, run the following command: -$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth -The output should indicate the inactive configuration option is set -to an appropriate integer between 1 and -; and should appear -before the pam_unix.so module as shown in the example below: -$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth -auth required pam_lastlog.so inactive= -auth sufficient pam_unix.so - Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? - - - - To verify that kernel parameter 'crypto.fips_enabled' is set properly, run the following command: -sysctl crypto.fips_enabled -The output should contain the following: -crypto.fips_enabled = 1 - Is it the case that crypto.fips_enabled is not 1? - - - - To check the ownership of /etc/crontab, -run the command: -$ ls -lL /etc/crontab -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/crontab does not have an owner of root? - - - - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -To find system executables directories that are group-writable or -world-writable, run the following command for each directory DIR -which contains system executables: -$ sudo find -L DIR -perm /022 -type d - Is it the case that any of these files are group-writable or world-writable? - - - - Verify that Oracle Linux 9 enforces a minimum -character password length with the following command: - -$ grep minlen /etc/security/pwquality.conf - -minlen = - Is it the case that the command does not return a "minlen" value of "<sub idref="var_password_pam_minlen" />" or greater, does not return a line, or the line is commented out? - - - - To check the group ownership of /etc/ipsec.d, -run the command: -$ ls -lL /etc/ipsec.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ipsec.d does not have a group owner of root? - - - - To check the ownership of /etc/cron.allow, -run the command: -$ ls -lL /etc/cron.allow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.allow does not have an owner of root? - - - - Verify Oracle Linux 9 is configured to lock the root account after -unsuccessful logon attempts with the command: - -$ grep even_deny_root /etc/security/faillock.conf -even_deny_root - Is it the case that the "even_deny_root" option is not set, is missing or commented out? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_defrtr -0. - - Is it the case that the correct value is not returned? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the creat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r creat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep creat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HARDENED_USERCOPY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling automount-open -If properly configured, the output for automount-openshould be false. -To ensure that users cannot enable automount opening in GNOME3, run the following: -$ grep 'automount-open' /etc/dconf/db/local.d/locks/* -If properly configured, the output for automount-open should be /org/gnome/desktop/media-handling/automount-open - Is it the case that GNOME automounting is not disabled? - - - - To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: - -$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Verify that Oracle Linux 9 is configured to take action in the event of allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep admin_space_left_action /etc/audit/auditd.conf - -admin_space_left_action = single - -If the value of the "admin_space_left_action" is not set to "single", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. - Is it the case that there is no evidence that real-time alerts are configured on the system? - - - - Run the following command to check if the line is present: -grep pam_wheel /etc/pam.d/su -The output should contain the following line: -auth required pam_wheel.so use_uid group= - Is it the case that the line is not in the file or it is commented? - - - - Verify the "/etc/security/faillock.conf" file is configured use a non-default faillock directory to ensure contents persist after reboot: - -$ sudo grep 'dir =' /etc/security/faillock.conf - -dir = /var/log/faillock - Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - - - To ensure the tally directory is configured correctly, run the following command: -$ sudo grep 'dir =' /etc/security/faillock.conf -The output should show that dir is set to something other than "/var/run/faillock" - Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes init_on_alloc=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*init_on_alloc=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*init_on_alloc=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'init_on_alloc=1' -The command should not return any output. - Is it the case that the kernel is not configured to zero out memory before allocation? - - - - Only strong MACs should be used. To verify that only strong -MACs are in use, run the following command: -$ sudo grep -i macs /etc/ssh/sshd_config -The output should contain only those MACs which are strong, namely, - hash functions. - Is it the case that MACs option is commented out or not using strong hash algorithms? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "umount" command with the following command: - -$ sudo auditctl -l | grep umount - --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-umount - Is it the case that the command does not return a line, or the line is commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes audit_backlog_limit=8192, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit_backlog_limit=8192.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*audit_backlog_limit=8192.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'audit_backlog_limit=8192' -The command should not return any output. - Is it the case that audit backlog limit is not configured? - - - - Run the following command to determine if the postfix package is installed: $ rpm -q postfix - Is it the case that the package is not installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BUG_ON_DATA_CORRUPTION /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/cron.deny, -run the command: -$ ls -lL /etc/cron.deny -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.deny does not have a group owner of root? - - - - The runtime status of the kernel.unprivileged_bpf_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.unprivileged_bpf_disabled -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.sysrq kernel parameter can be queried -by running the following command: -$ sysctl kernel.sysrq -0. - - Is it the case that the correct value is not returned? - - - - - -Run the following command to determine the current status of the -systemd-journald service: -$ sudo systemctl is-active systemd-journald -If the service is running, it should return the following: active - Is it the case that the systemd-journald service is not running? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one special character with the following command: - -$ sudo grep ocredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -ocredit = - Is it the case that value of "ocredit" is a positive number or is commented out? - - - - Verify that all local interactive user initialization file executable search path statements do not contain statements that will reference a working directory other than user home directories with the following commands: - -$ sudo grep -i path= /home/*/.* - -/home/[localinteractiveuser]/.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin - Is it the case that any local interactive user initialization files have executable search path statements that include directories outside of their home directory and is not documented with the ISSO as an operational requirement? - - - - Verify the audit log directories have a correct mode or less permissive mode. - -Find the location of the audit logs: - -$ sudo grep "^log_file" /etc/audit/auditd.conf - - -Find the group that owns audit logs: - -$ sudo grep "^log_group" /etc/audit/auditd.conf - - -Run the following command to check the mode of the system audit logs: - -$ sudo stat -c "%a %n" [audit_log_directory] - -Replace "[audit_log_directory]" to the correct audit log directory path, by default this location is "/var/log/audit". - - -If the log_group is "root" or is not set, the correct permissions are 0700, otherwise they are 0750. - Is it the case that audit logs have a more permissive mode? - - - - To determine the config value the kernel was built with, run the following command: -$ grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config.* -For each kernel installed, a line with value should be returned. -If the system architecture is x86_64, the value should be 65536. -If the system architecture is aarch64, the value should be 32768. - Is it the case that the kernel was not built with the required value? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling automount -If properly configured, the output for automount should be false. -To ensure that users cannot enable automount in GNOME3, run the following: -$ grep 'automount' /etc/dconf/db/local.d/locks/* -If properly configured, the output for automount should be /org/gnome/desktop/media-handling/automount - Is it the case that GNOME automounting is not disabled? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r open /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep open /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine how the SSH daemon's HostbasedAuthentication option is set, run the following command: - -$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - -To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit - -To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* - Is it the case that ? - - - - Verify the nosuid option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . nosuid . . . - - Is it the case that the "/boot" file system does not have the "nosuid" option set? - - - - To verify that Audit Daemon is configured to write logs to the disk, run the -following command: -$ sudo grep write_logs /etc/audit/auditd.conf -The output should return the following: -write_logs = yes - Is it the case that write_logs isn't set to yes? - - - - Verify Oracle Linux 9 notifies the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep -w space_left_action /etc/audit/auditd.conf - -space_left_action = - -If the value of the "space_left_action" is not set to "", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. - Is it the case that there is no evidence that real-time alerts are configured on the system? - - - - The runtime status of the net.ipv6.conf.all.max_addresses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.max_addresses -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.arp_filter kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.arp_filter -. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_FORCE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify the system commands contained in the following directories are owned by "root" with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin ! -user root -exec ls -l {} \; - Is it the case that any system commands are found to not be owned by root? - - - - To verify the password reuse setting is compliant, run the following command: -$ grep remember /etc/pam.d/system-auth -The output should show the following at the end of the line: -remember= - - -In newer systems, the pam_pwhistory PAM module options can also be set in -"/etc/security/pwhistory.conf" file. Use the following command to verify: -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory remember option must be configured only in one file. - Is it the case that the value of remember is not equal to or greater than the expected value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_VSYSCALL_EMULATE /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules -The output has to be exactly as follows: -## Unsuccessful file creation (open with O_CREAT) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create - Is it the case that the file does not exist or the content differs? - - - - To check the group ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/user.cfg does not have a group owner of root? - - - - To ensure that the GPG key is installed, run: -$ rpm -q --queryformat "%{SUMMARY}\n" gpg-pubkey -The command should return the string below: -gpg(Oracle OSS group (Open Source Software group) <build@oss.oracle.com> - Is it the case that the Oracle GPG Key is not installed? - - - - To verify that Audit Daemon is configured to include local events, run the -following command: -$ sudo grep local_events /etc/audit/auditd.conf -The output should return the following: -local_events = yes - Is it the case that local_events isn't set to yes? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STACKPROTECTOR /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify the grpquota option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . grpquota . . . - - Is it the case that the "/home" file system does not have the "grpquota" option set? - - - - Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file -and is configured to prohibit password reuse for a minimum of -generations. - -Verify the "/etc/pam.d/password-auth" file with the following command: - -$ grep pam_pwhistory.so /etc/pam.d/password-auth -password pam_pwhistory.so use_authtok remember= - - -Verify the "/etc/security/pwhistory.conf" file using the following command: - -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory.so "remember" option must be configured only in one file. - Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in -/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set -with a value less than "<sub idref="var_password_pam_remember" />"? - - - - Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "postdrop" command with the following command: - -$ sudo auditctl -l | grep postdrop - --a always,exit -F path=/usr/bin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postdrop - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers.d/" with the following command: - -$ sudo auditctl -l | grep/etc/sudoers.d - --w /etc/sudoers.d/ -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv6.conf.all.forwarding kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.forwarding -0. -The ability to forward packets is only appropriate for routers. - Is it the case that IP forwarding value is "1" and the system is not router? - - - - To determine if the system is configured to audit attempts to -alter time via the /etc/localtime file, run the following -command: -$ sudo auditctl -l | grep "watch=/etc/localtime" -If the system is configured to audit this activity, it will return a line. - Is it the case that the system is not configured to audit time changes? - - - - The runtime status of the net.ipv4.conf.all.forwarding kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.forwarding -0. -The ability to forward packets is only appropriate for routers. - Is it the case that IP forwarding value is "1" and the system is not router? - - - - Run the following command to determine if the fapolicyd package is installed: $ rpm -q fapolicyd - Is it the case that the fapolicyd package is not installed? - - - - -To ensure the login warning banner text is properly set, run the following: -$ grep banner-message-text /etc/dconf/db/local.d/* -If properly configured, the proper banner text will appear. -To ensure the login warning banner text is locked and cannot be changed by a user, run the following: -$ grep banner-message-text /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/banner-message-text. - Is it the case that it does not? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes spectre_v2=on, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spectre_v2=on.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*spectre_v2=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'spectre_v2=on' -The command should not return any output. - Is it the case that spectre_v2 mitigation is not enforced? - - - - The runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_source_route -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.autoconf kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.autoconf -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the vm.mmap_min_addr kernel parameter can be queried -by running the following command: -$ sysctl vm.mmap_min_addr -65536. - - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/ipsec.conf, -run the command: -$ ls -l /etc/ipsec.conf -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/ipsec.conf does not have unix mode 0644? - - - - The runtime status of the net.ipv4.tcp_syncookies kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.tcp_syncookies -1. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_ARM64_SW_TTBR0_PAN /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to prevent the usage of the ipv6 on -network interfaces, it will contain a line of the form: -net.ipv6.conf.default.disable_ipv6 = 1 -Such lines may be inside any file in the /etc/sysctl.d directory. -This permits insertion of the IPv6 kernel module (which other parts of the -system expect to be present), but otherwise keeps network interfaces -from using IPv6. Run the following command to search for such lines in all -files in /etc/sysctl.d: -$ grep -r ipv6 /etc/sysctl.d - Is it the case that the ipv6 support is disabled by default on network interfaces? - - - - Verify the nosuid option is configured for the /srv mount point, - run the following command: - $ sudo mount | grep '\s/srv\s' - . . . /srv . . . nosuid . . . - - Is it the case that the "/srv" file system does not have the "nosuid" option set? - - - - To ensure the user list is disabled, run the following command: -$ grep disable-user-list /etc/dconf/db/local.d/* -The output should be true. -To ensure that users cannot enable displaying the user list, run the following: -$ grep disable-user-list /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/disable-user-list - Is it the case that disable-user-list has not been configured or is not disabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_IA32_EMULATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that GRUB_DISABLE_RECOVERY is set to true in /etc/default/grub to disable recovery boot. -Run the following command: - -$ sudo grep GRUB_DISABLE_RECOVERY /etc/default/grub - Is it the case that GRUB_DISABLE_RECOVERY is not set to true or is missing? + + The file permissions for all log files written by rsyslog should +be set to 640, or more restrictive. These log files are determined by the +second part of each Rule line in /etc/rsyslog.conf and typically +all appear in /var/log. To see the permissions of a given log +file, run the following command: +$ ls -l LOGFILE +The permissions should be 640, or more restrictive. + Is it the case that the permissions are not correct? @@ -260276,318 +284500,244 @@ input(type="imudp" port="514") Is it the case that rsyslog accepts remote messages and is not documented as a log aggregation system? - - To verify all accounts have unique names, run the following command: -$ sudo getent passwd | awk -F: '{ print $1}' | uniq -d -No output should be returned. - Is it the case that a line is returned? - - - - To check the group ownership of /etc/cron.weekly, -run the command: -$ ls -lL /etc/cron.weekly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.weekly does not have a group owner of root? - - - - Check that Oracle Linux 9 has the packages for smart card support installed. - -Run the following command to determine if the openssl-pkcs11 package is installed: -$ rpm -q openssl-pkcs11 - Is it the case that smartcard software is not installed? - - - - To verify if the OpenSSH server uses defined ciphers in the Crypto Policy, run: -$ grep -Po '(-oCiphers=\S+)' /etc/crypto-policies/back-ends/opensshserver.config -and verify that the line matches: --oCiphers= - Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? - - - - To check the group ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes pti=on, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*pti=on.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*pti=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'pti=on' -The command should not return any output. - Is it the case that Kernel page-table isolation is not enabled? - - - - To check the system for the existence of any .netrc files, + + To verify that remote access methods are logging to rsyslog, run the following command: -$ sudo find /home -xdev -name .netrc - Is it the case that any .netrc files exist? + +grep -rE '(auth.\*|authpriv.\*|daemon.\*)' /etc/rsyslog.* + +The output should contain auth.*, authpriv.*, and daemon.* +pointing to a log file. + Is it the case that remote access methods are not logging to rsyslog? - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/tallylog" with the following command: - -$ sudo auditctl -l | grep /var/log/tallylog - --w /var/log/tallylog -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? + + To ensure logs are sent to a remote host, examine the file +/etc/rsyslog.conf. +If using UDP, a line similar to the following should be present: + *.* @ +or +*.* action(type="omfwd" ... target="" protocol="udp") +If using TCP, a line similar to the following should be present: + *.* @@ +or +*.* action(type="omfwd" ... target="" protocol="tcp") +If using RELP, a line similar to the following should be present: + *.* :omrelp: +or +*.* action(type="omfwd" ... target="" protocol="relp") + Is it the case that no evidence that the audit logs are being off-loaded to another system or media? - + + To verify that rsyslog's Forwarding Output Module is configured +to use TLS for logging to remote server, run the following command: +$ grep omfwd /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should include record similar to +action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" + StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on") + +where the <remote system> present in the configuration line above must be a valid IP address or a host name of the remote logging server. + Is it the case that omfwd is not configured with gtls and AuthMode? + + + + To verify that rsyslog's Forwarding Output Module has CA certificate +configured for its TLS connections to remote server, run the following command: +$ grep DefaultNetstreamDriverCAFile /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should include record similar to +global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem") +where the path to the CA file (/etc/pki/tls/cert.pem in case above) must point to the correct CA certificate. + Is it the case that CA certificate for rsyslog remote logging via TLS is not set? + + + -Determine the audit log group by running the following command: - -$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf - -Then, check that all directories within the /var/log/audit directory are owned by the group specified as log_group or by root if the log_group is not specified. -Run the following command: - -$ sudo find /var/log/audit -type d -printf "%p %g\n" - -All listed directories must be owned by the log_group or by root if the log_group is not specified. - Is it the case that there is a directory owned by different group? +Run the following command to determine if the auditadm_exec_content SELinux boolean is enabled: +$ getsebool auditadm_exec_content +If properly configured, the output should show the following: +auditadm_exec_content --> on + Is it the case that auditadm_exec_content is not enabled? - - To verify the assigned home directory of all interactive user home directories -have a mode of 0750 or less permissive, run the following command: -$ sudo ls -l /home -Inspect the output for any directories with incorrect permissions. - Is it the case that they are more permissive? + + +Run the following command to determine if the authlogin_nsswitch_use_ldap SELinux boolean is disabled: +$ getsebool authlogin_nsswitch_use_ldap +If properly configured, the output should show the following: +authlogin_nsswitch_use_ldap --> off + Is it the case that authlogin_nsswitch_use_ldap is not disabled? - - Run the following command to determine if the nss-tools package is installed: $ rpm -q nss-tools - Is it the case that the package is not installed? + + +Run the following command to determine if the authlogin_radius SELinux boolean is disabled: +$ getsebool authlogin_radius +If properly configured, the output should show the following: +authlogin_radius --> off + Is it the case that authlogin_radius is not disabled? - - To verify that auditing of privileged command use is configured, run the + + +Run the following command to get the current configured value for deny_execmem +SELinux boolean: +$ getsebool deny_execmem +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that deny_execmem is not set as expected? + + + + +Run the following command to determine if the kerberos_enabled SELinux boolean is enabled: +$ getsebool kerberos_enabled +If properly configured, the output should show the following: +kerberos_enabled --> on + Is it the case that kerberos_enabled is not enabled? + + + + +Run the following command to get the current configured value for polyinstantiation_enabled +SELinux boolean: +$ getsebool polyinstantiation_enabled +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that polyinstantiation_enabled is not set as expected? + + + + +Run the following command to get the current configured value for secure_mode_insmod +SELinux boolean: +$ getsebool secure_mode_insmod +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that secure_mode_insmod is not set as expected? + + + + +Run the following command to determine if the selinuxuser_execheap SELinux boolean is disabled: +$ getsebool selinuxuser_execheap +If properly configured, the output should show the following: +selinuxuser_execheap --> off + Is it the case that selinuxuser_execheap is not disabled? + + + + +Run the following command to determine if the selinuxuser_execmod SELinux boolean is enabled: +$ getsebool selinuxuser_execmod +If properly configured, the output should show the following: +selinuxuser_execmod --> on + Is it the case that selinuxuser_execmod is not enabled? + + + + +Run the following command to determine if the selinuxuser_execstack SELinux boolean is disabled: +$ getsebool selinuxuser_execstack +If properly configured, the output should show the following: +selinuxuser_execstack --> off + Is it the case that selinuxuser_execstack is not disabled? + + + + +Run the following command to determine if the ssh_sysadm_login SELinux boolean is disabled: +$ getsebool ssh_sysadm_login +If properly configured, the output should show the following: +ssh_sysadm_login --> off + Is it the case that ssh_sysadm_login is not disabled? + + + + Check that Secure Boot is enabled with the mokutil command. + +When Secure Boot is enabled: + +mokutil --sb-state +SecureBoot enabled + + +When Secure Boot is disabled: + +mokutil --sb-state +Failed to read SecureBoot + + +or: + +mokutil --sb-state +SecureBoot disabled + + Is it the case that Secure Boot is not enabled? + + + + To check for virtual console entries which permit root login, run the following command: -$ sudo grep '\bat\b' /etc/audit/audit.rules /etc/audit/rules.d/* -It should return a relevant line in the audit rules. - Is it the case that the command does not return a line, or the line is commented out? +$ sudo grep ^vc/[0-9] /etc/securetty +If any output is returned, then root logins over virtual console devices is permitted. + Is it the case that root login over virtual console devices is permitted? - - To check the group ownership of /etc/ssh/*_key, -run the command: -$ ls -lL /etc/ssh/*_key -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/*_key does not have a group owner of root? - - - - To check that the sshd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled sshd -Output should indicate the sshd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled sshd disabled + + Verify Oracle Linux 9 security patches and updates are installed and up to date. +Updates are required to be applied with a frequency determined by organizational policy. -Run the following command to verify sshd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active sshd -If the service is not running the command will return the following output: -inactive -The service will also be masked, to check that the sshd is masked, run the following command: -$ sudo systemctl show sshd | grep "LoadState\|UnitFileState" +Typical update frequency may be overridden by Information Assurance Vulnerability Alert (IAVA) notifications from CYBERCOM. + Is it the case that Oracle Linux 9 is in non-compliance with the organizational patching policy? + + + + To check for incorrectly labeled device files, run following commands: +$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n" +$ sudo find /dev -context *:unlabeled_t:* \( -type c -o -type b \) -printf "%p %Z\n" +It should produce no output in a well-configured system. + Is it the case that there is output? + + + + Ensure there are no unconfined daemons running on the system, +the following command should produce no output: +$ sudo ps -eZ | grep "unconfined_service_t" + Is it the case that There are unconfined daemons running on the system? + + + + Ensure that Oracle Linux 9 does not disable SELinux. -If the service is masked the command will return the following outputs: +Check if "SELinux" is active and in "enforcing" or "permissive" mode with the following command: -LoadState=masked +$ sudo getenforce +Enforcing +-OR- +Permissive + Is it the case that SELinux is disabled? + + + + Verify the SELINUX on Oracle Linux 9 is using the policy with the following command: -UnitFileState=masked - Is it the case that the "sshd" is loaded and not masked? - - - - Run the following command to ensure that /var/tmp is configured as a -polyinstantiated directory: -$ sudo grep /var/tmp /etc/security/namespace.conf -The output should return the following: -/var/tmp /var/tmp/tmp-inst/ level root,adm - Is it the case that is not configured? - - - - To check the ownership of /etc/cron.daily, -run the command: -$ ls -lL /etc/cron.daily -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.daily does not have an owner of root? - - - - Run the following command to determine the current status of the logrotate timer: $ sudo systemctl is-active logrotate.timer If the timer is running, it should return the following: active - Is it the case that logrotate timer is not enabled? - - - - To verify the assigned home directory of all interactive users is group- -owned by that users primary GID, run the following command: -# ls -ld $(awk -F: '($3>=1000)&&($7 !~ /nologin/){print $6}' /etc/passwd) - Is it the case that the group ownership is incorrect? - - - - Inspect the file /etc/sysconfig/iptables to determine -the default policy for the INPUT chain. It should be set to DROP: -$ sudo grep ":INPUT" /etc/sysconfig/iptables - Is it the case that the default policy for the INPUT chain is not set to DROP? - - - - The existence of the file /etc/hosts.equiv or a file named -.rhosts inside a user home directory indicates the presence -of an Rsh trust relationship. - Is it the case that these files exist? - - - - To find world-writable directories that lack the sticky bit, run the following command: -$ sudo find / -type d \( -perm -0002 -a ! -perm -1000 \) -print 2>/dev/null -fixtext: |- -Configure all world-writable directories to have the sticky bit set to prevent unauthorized and unintended information transferred via shared system resources. +$ sestatus | grep policy -Set the sticky bit on all world-writable directories using the command, replace "[World-Writable Directory]" with any directory path missing the sticky bit: +Loaded policy name: + Is it the case that the loaded policy name is not "<sub idref="var_selinux_policy_name" />"? + + + + Ensure that Oracle Linux 9 verifies correct operation of security functions. -$ chmod a+t [World-Writable Directory] -srg_requirement: -A sticky bit must be set on all Oracle Linux 9 public directories to prevent unauthorized and unintended information transferred via shared system resources. - Is it the case that any world-writable directories are missing the sticky bit? - - - - The runtime status of the net.ipv6.conf.all.autoconf kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.autoconf -0. +Check if "SELinux" is active and in "" mode with the following command: - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_TABLE_ISOLATION /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "kmod" command with the following command: +$ sudo getenforce -$ sudo auditctl -l | grep kmod - --a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-kmod - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the telnet-server package is installed: -$ rpm -q telnet-server - Is it the case that the package is installed? - - - - To check the ownership of /etc/selinux, -run the command: -$ ls -lL /etc/selinux -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/selinux does not have an owner of root? - - - - Run the following command to determine if the openscap-scanner package is installed: $ rpm -q openscap-scanner - Is it the case that the package is not installed? - - - - Verify Oracle Linux 9 enforces a delay of at least seconds between console logon prompts following a failed logon attempt with the following command: - -$ sudo grep -i "FAIL_DELAY" /etc/login.defs -FAIL_DELAY - Is it the case that the value of "FAIL_DELAY" is not set to "<sub idref="var_accounts_fail_delay" />" or greater, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -delete_module system call, run the following command: -$ sudo grep "delete_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the ownership of /etc/shadow, -run the command: -$ ls -lL /etc/shadow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shadow does not have an owner of root? - - - - To check the ownership of /etc/crypttab, -run the command: -$ ls -lL /etc/crypttab -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/crypttab does not have an owner of root? - - - - To check the permissions of /etc/chrony.keys, -run the command: -$ ls -l /etc/chrony.keys -If properly configured, the output should indicate the following permissions: -0640 - Is it the case that /etc/chrony.keys does not have unix mode 0640? - - - - Shared libraries are stored in the following directories: -/lib -/lib64 -/usr/lib -/usr/lib64 - -To find shared libraries that are group-writable or world-writable, -run the following command for each directory DIR which contains shared libraries: -$ sudo find -L DIR -perm /022 -type d - Is it the case that any of these files are group-writable or world-writable? - - - - To determine if the system is configured to audit calls to the -fchown system call, run the following command: -$ sudo grep "fchown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? + Is it the case that SELINUX is not set to enforcing? @@ -260615,58 +284765,129 @@ UnitFileState=masked Is it the case that the "atd" is loaded and not masked? - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers" with the following command: + + -$ sudo auditctl -l | grep /etc/sudoers +Run the following command to determine the current status of the +auditd service: +$ sudo systemctl is-active auditd +If the service is running, it should return the following: active + Is it the case that the auditd service is not running? + + + + To check that the autofs service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled autofs +Output should indicate the autofs service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled autofs disabled --w /etc/sudoers -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STACKPROTECTOR_STRONG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Inspect the list of enabled firewall ports and verify they are configured correctly by running -the following command: +Run the following command to verify autofs is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active autofs -$ sudo firewall-cmd --list-all +If the service is not running the command will return the following output: +inactive -Ask the System Administrator for the site or program Ports, Protocols, and Services Management Component Local Service Assessment (PPSM CLSA). Verify the services allowed by the firewall match the PPSM CLSA. - Is it the case that there are additional ports, protocols, or services that are not in the PPSM CLSA, or there are ports, protocols, or services that are prohibited by the PPSM Category Assurance List (CAL), or there are no firewall rules configured? +The service will also be masked, to check that the autofs is masked, run the following command: +$ sudo systemctl show autofs | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "autofs" is loaded and not masked? - - Run the following command to determine if the policycoreutils-python-utils package is installed: $ rpm -q policycoreutils-python-utils - Is it the case that the package is not installed? + + To check that the avahi-daemon service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled avahi-daemon +Output should indicate the avahi-daemon service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled avahi-daemon disabled + +Run the following command to verify avahi-daemon is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active avahi-daemon + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the avahi-daemon is masked, run the following command: +$ sudo systemctl show avahi-daemon | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "avahi-daemon" is loaded and not masked? - - To determine that AIDE is configured for FIPS 140-2 file hashing, run the following command: -$ grep sha512 /etc/aide.conf -Verify that the sha512 option is added to the correct ruleset. - Is it the case that the sha512 option is missing or not added to the correct ruleset? + + + +Run the following command to determine the current status of the +chronyd service: +$ sudo systemctl is-active chronyd +If the service is running, it should return the following: active + Is it the case that the chronyd process is not running? - - Verify that there are no shosts.equiv files on the system, run the following command: -$ find / -name shosts.equiv - Is it the case that shosts.equiv files exist? + + + +Run the following command to determine the current status of the +crond service: +$ sudo systemctl is-active crond +If the service is running, it should return the following: active + Is it the case that ? - - Make sure that the kernel is not disabling SMAP with the following -commands. -grep -q nosmap /boot/config-`uname -r` -If the command returns a line, it means that SMAP is being disabled. - Is it the case that the kernel is configured to disable SMAP? + + To check that the debug-shell service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled debug-shell +Output should indicate the debug-shell service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled debug-shell disabled + +Run the following command to verify debug-shell is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active debug-shell + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the debug-shell is masked, run the following command: +$ sudo systemctl show debug-shell | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "debug-shell" is loaded and not masked? + + + + + +Run the following command to determine the current status of the +fapolicyd service: +$ sudo systemctl is-active fapolicyd +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + + +Run the following command to determine the current status of the +firewalld service: +$ sudo systemctl is-active firewalld +If the service is running, it should return the following: active + Is it the case that the "firewalld" service is disabled, masked, or not started.? @@ -260679,283 +284900,99 @@ If the service is running, it should return the following: active Is it the case that ? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - -If the system is configured to prevent the loading of the can kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + + To check that the kdump service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled kdump +Output should indicate the kdump service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled kdump disabled -These lines can also instruct the module loading system to ignore the can kernel module via blacklist keyword. +Run the following command to verify kdump is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active kdump -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r can /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the kdump is masked, run the following command: +$ sudo systemctl show kdump | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "kdump" is loaded and not masked? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_REFCOUNT_FULL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? + + To check that the nftables service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled nftables +Output should indicate the nftables service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled nftables disabled + +Run the following command to verify nftables is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active nftables + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the nftables is masked, run the following command: +$ sudo systemctl show nftables | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "nftables" is loaded and not masked? - + + To check that the oddjobd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled oddjobd +Output should indicate the oddjobd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled oddjobd disabled + +Run the following command to verify oddjobd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active oddjobd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the oddjobd is masked, run the following command: +$ sudo systemctl show oddjobd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "oddjobd" is loaded and not masked? + + + Run the following command to determine the current status of the -rsyslog service: -$ sudo systemctl is-active rsyslog +pcscd service: +$ sudo systemctl is-active pcscd If the service is running, it should return the following: active - Is it the case that the "rsyslog" service is disabled, masked, or not started.? + Is it the case that the pcscd service is not enabled? - - To check for serial port entries which permit root login, -run the following command: -$ sudo grep ^ttyS/[0-9] /etc/securetty -If any output is returned, then root login over serial ports is permitted. - Is it the case that root login over serial ports is permitted? - - - - Verify the audit system is configured to take an appropriate action when the internal event queue is full: -$ sudo grep -i overflow_action /etc/audit/auditd.conf + + -The output should contain overflow_action = syslog - -If the value of the "overflow_action" option is not set to syslog, -single, halt or the line is commented out, ask the System Administrator -to indicate how the audit logs are off-loaded to a different system or media. - Is it the case that auditd overflow action is not set correctly? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "su" command with the following command: - -$ sudo auditctl -l | grep su - --a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged-su - Is it the case that the command does not return a line, or the line is commented out? - - - - To ensure only SNMPv3 or newer is used, run the following command: -$ sudo grep 'rocommunity\|rwcommunity\|com2sec' /etc/snmp/snmpd.conf | grep -v "^#" -There should be no output. - Is it the case that there is output? - - - - The runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - To check the ownership of /etc/sudoers.d, -run the command: -$ ls -lL /etc/sudoers.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sudoers.d does not have an owner of root? - - - - To obtain a list of all users and the content of their shadow password field, run the command: -$ sudo readarray -t systemaccounts -Verify if all accounts are locked. - Is it the case that system accounts are not locked? - - - - To determine how the SSH daemon's PrintLastLog option is set, run the following command: - -$ sudo grep -i PrintLastLog /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To verify the nosuid option is configured for all NFS mounts, run -the following command: -$ mount | grep nfs -All NFS mounts should show the nosuid setting in parentheses. This -is not applicable if NFS is not implemented. - Is it the case that the setting does not show? - - - - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/local/bin -/usr/local/sbin -/usr/sbin -For each of these directories, run the following command to find files -not owned by root: -$ sudo find -L DIR/ ! -user root -type d -exec chown root {} \; - Is it the case that any system executables directories are found to not be owned by root? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_rtr_pref -0. - - Is it the case that the correct value is not returned? - - - - To check if RekeyLimit is set correctly, run the following command: -$ sudo grep RekeyLimit /etc/ssh/ssh_config.d/*.conf -If configured properly, output should be -/etc/ssh/ssh_config.d/02-rekey-limit.conf: -RekeyLimit -Check also the main configuration file with the following command: -$ sudo grep RekeyLimit /etc/ssh/ssh_config -The command should not return any output. - Is it the case that it is commented out or is not set? - - - - Verify that sshd isn't configured to ignore the system wide cryptographic policy. - -Check that the CRYPTO_POLICY variable is not set or is commented out in the -/etc/sysconfig/sshd. - -Run the following command: - -$ sudo grep CRYPTO_POLICY /etc/sysconfig/sshd - Is it the case that the CRYPTO_POLICY variable is set or is not commented out in the /etc/sysconfig/sshd? - - - - Verify the audit system prevents unauthorized changes with the following command: - -$ sudo grep "^\s*[^#]" /etc/audit/audit.rules | tail -1 --e 2 - - Is it the case that the audit system is not set to be immutable by adding the "-e 2" option to the end of "/etc/audit/audit.rules"? - - - - To verify that SSSD is configured for PAM services, run the following command: -$ sudo grep services /etc/sssd/sssd.conf -If configured properly, output should be similar to -services = pam - Is it the case that it does not exist or 'pam' is not added to the 'services' option under the 'sssd' section? - - - - To check the minimum password length, run the command: -$ grep PASS_MIN_LEN /etc/login.defs -The DoD requirement is 15. - Is it the case that it is not set to the required value? - - - - To check the permissions of /etc/at.allow, -run the command: -$ ls -l /etc/at.allow -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/at.allow does not have unix mode -rw-r-----? - - - - To check the group ownership of /etc/crypttab, -run the command: -$ ls -lL /etc/crypttab -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/crypttab does not have a group owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLAB_FREELIST_HARDENED /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the kernel.panic_on_oops kernel parameter can be queried -by running the following command: -$ sysctl kernel.panic_on_oops -1. - - Is it the case that the correct value is not returned? - - - - Run the following command to ensure the default FORWARD policy is DROP: -grep ":FORWARD" /etc/sysconfig/iptables -The output should be similar to the following: -$ sudo grep ":FORWARD" /etc/sysconfig/iptables -:FORWARD DROP [0:0 - Is it the case that the default policy for the FORWARD chain is not set to DROP? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BUG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/shadow, -run the command: -$ ls -lL /etc/shadow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shadow does not have a group owner of root? - - - - To ensure that XDMCP is disabled in /etc/gdm/custom.conf, run the following command: -grep -Pzo "\[xdmcp\]\nEnable=false" /etc/gdm/custom.conf -The output should return the following: - -[xdmcp] -Enable=false - - Is it the case that the Enable is not set to false or is missing in the xdmcp section of the /etc/gdm/custom.conf gdm configuration file? - - - - To ensure ClientAliveInterval is set correctly, run the following command: - -$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config - -If properly configured, the output should be: -ClientAliveCountMax 0 - -In this case, the SSH timeout occurs precisely when -the ClientAliveInterval is set. - Is it the case that it is commented out or not configured properly? +Run the following command to determine the current status of the +postfix service: +$ sudo systemctl is-active postfix +If the service is running, it should return the following: active + Is it the case that the system is not a cross domain solution and the service is not enabled? @@ -260983,569 +285020,44 @@ UnitFileState=masked Is it the case that the "rdisc" is loaded and not masked? - - Verify that Oracle Linux 9 enforces password complexity rules for the root account. - -Check if root user is required to use complex passwords with the following command: - -$ grep enforce_for_root /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:enforce_for_root - Is it the case that "enforce_for_root" is commented or missing? - - - - Run the following command to determine if the tuned package is installed: -$ rpm -q tuned - Is it the case that the package is installed? - - - - To check if the system motd banner is compliant, -run the following command: -$ cat /etc/motd - Is it the case that it does not display the required banner? - - - - To check the permissions of /etc/audit/auditd.conf, -run the command: -$ ls -l /etc/audit/auditd.conf -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/audit/auditd.conf does not have unix mode -rw-r-----? - - - - Verify the NX (no-execution) bit flag is set on the system. - -Check that the no-execution bit flag is set with the following commands: - -$ sudo dmesg | grep NX - -[ 0.000000] NX (Execute Disable) protection: active - -If "dmesg" does not show "NX (Execute Disable) protection" active, check the cpuinfo settings with the following command: - -$ sudo grep flags /proc/cpuinfo -flags : fpu vme de pse tsc ms nx rdtscp lm constant_ts - -The output should contain the "nx" flag. - Is it the case that NX is disabled? - - - - Verify the operating system routinely checks the baseline configuration for unauthorized changes. - -To determine that periodic AIDE execution has been scheduled, run the following command: -$ grep aide /etc/crontab -The output should return something similar to the following: -05 4 * * * root /usr/sbin/aide --check - -NOTE: The usage of special cron times, such as @daily or @weekly, is acceptable. - Is it the case that AIDE is not configured to scan periodically? - - - - Verify that Oracle Linux 9 contains no duplicate User IDs (UIDs) for interactive users. - -Check that the operating system contains no duplicate UIDs for interactive users with the following command: - -$ sudo awk -F ":" 'list[$3]++{print $1, $3}' /etc/passwd - Is it the case that output is produced and the accounts listed are interactive user accounts? - - - - Run the following command to determine if the bind package is installed: -$ rpm -q bind - Is it the case that the package is installed? - - - - Verify that a separate file system/partition has been created for /dev/shm with the following command: - -$ mountpoint /dev/shm - - Is it the case that "/dev/shm is not a mountpoint" is returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODIFY_LDT_SYSCALL /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setfiles" command with the following command: - -$ sudo auditctl -l | grep setfiles - --a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update - Is it the case that the command does not return a line, or the line is commented out? - - - + -Run the following command to determine if the auditadm_exec_content SELinux boolean is enabled: -$ getsebool auditadm_exec_content -If properly configured, the output should show the following: -auditadm_exec_content --> on - Is it the case that auditadm_exec_content is not enabled? - - - - Run the following command to determine if the McAfeeTP package is installed: $ rpm -q McAfeeTP - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 does not have unauthorized IP tunnels configured. +To check that the rlogin service is disabled in system boot configuration with xinetd, run the following command: +$ chkconfig rlogin --list +Output should indicate the rlogin service has either not been installed, or has been disabled, as shown in the example below: +$ chkconfig rlogin --list +Note: This output shows SysV services only and does not include native +systemd services. SysV configuration data might be overridden by native +systemd configuration. -# yum list installed libreswan -libreswan.x86-64 3.20-5.el7_4 +If you want to list systemd services use 'systemctl list-unit-files'. +To see services enabled on particular target use +'systemctl list-dependencies [target]'. +rlogin off -If "libreswan" is installed, check to see if the "IPsec" service is active with the following command: +To check that the rlogin socket is disabled in system boot configuration with systemd, run the following command: +$ systemctl is-enabled rlogin +Output should indicate the rlogin socket has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled rlogindisabled -# systemctl status ipsec -ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec -Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) -Active: inactive (dead) +Run the following command to verify rlogin is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active rlogin +If the socket is not running the command will return the following output: +inactive -If the "IPsec" service is active, check for configured IPsec connections (conn), perform the following: -grep -rni conn /etc/ipsec.conf /etc/ipsec.d/ -Verify any returned results for organizational approval. - Is it the case that the IPSec tunnels are not approved? - - - - To ensure the screensaver is configured to be blank, run the following command: -$ gsettings get org.gnome.desktop.screensaver picture-uri -If properly configured, the output should be ''. +The socket will also be masked, to check that the rlogin is masked, run the following command: +$ sudo systemctl show rlogin | grep "LoadState\|UnitFileState" -To ensure that users cannot set the screensaver background, run the following: -$ grep picture-uri /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/screensaver/picture-uri - Is it the case that it is not set or configured properly? - - - - Run the following command to determine if the gssproxy package is installed: -$ rpm -q gssproxy - Is it the case that the package is installed? - - - - Verify that Oracle Linux 9 has a DNS mode configured in Network Manager. +If the socket is masked the command will return the following outputs: -$ NetworkManager --print-config -[main] -dns= - Is it the case that the dns key under main does not exist or is not set to "none" or "default"? - - - - Verify the nosuid option is configured for the /opt mount point, - run the following command: - $ sudo mount | grep '\s/opt\s' - . . . /opt . . . nosuid . . . +LoadState=masked - Is it the case that the "/opt" file system does not have the "nosuid" option set? - - - - To ensure write permissions are disabled for group and other - for each element in root's path, run the following command: -# ls -ld DIR - Is it the case that group or other write permissions exist? - - - - Verify Oracle Linux 9 is configured to lock an account until released by an administrator -after unsuccessful logon -attempts with the command: - -$ grep 'unlock_time =' /etc/security/faillock.conf -unlock_time = - Is it the case that the "unlock_time" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_unlock_time" />", -the line is missing, or commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_YAMA /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify that OpenSSL uses the system crypto policy, check out that the OpenSSL config file -/etc/pki/tls/openssl.cnf contains the [ crypto_policy ] section with the -.include = /etc/crypto-policies/back-ends/opensslcnf.config directive: - -$ sudo grep '\.include\s* /etc/crypto-policies/back-ends/opensslcnf.config$' /etc/pki/tls/openssl.cnf. - Is it the case that the OpenSSL config file doesn't contain the whole section, -or the section doesn't contain the <pre>.include = /etc/crypto-policies/back-ends/opensslcnf.config</pre> directive? - - - - Determine where the audit logs are stored with the following command: - -$ sudo grep -iw log_file /etc/audit/auditd.conf - -log_file = /var/log/audit/audit.log - -Determine the owner of the audit log directory by using the output of the above command -(default: "/var/log/audit/"). Run the following command with the correct audit log directory -path: - -$ sudo ls -ld /var/log/audit - -drwx------ 2 root root 23 Jun 11 11:56 /var/log/audit - -The audit log directory must be owned by "root" - Is it the case that the directory is not owned by root? - - - - To verify all local initialization files for interactive users are owned by the -primary user, run the following command: -$ sudo ls -al /home/USER/.* -The user initialization files should be owned by USER. - Is it the case that they are not? - - - - Check that the symlink exists and target the correct Kerberos crypto policy, with the following command: -file /etc/krb5.conf.d/crypto-policies -If command ouput shows the following line, Kerberos is configured to use the system-wide crypto policy. -/etc/krb5.conf.d/crypto-policies: symbolic link to /etc/crypto-policies/back-ends/krb5.config - Is it the case that the symlink does not exist or points to a different target? - - - - The runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.drop_gratuitous_arp -1. - - Is it the case that the correct value is not returned? - - - - To determine that AIDE is verifying ACLs, run the following command: -$ grep acl /etc/aide.conf -Verify that the acl option is added to the correct ruleset. - Is it the case that the acl option is missing or not added to the correct ruleset? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes audit=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*audit=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'audit=1' -The command should not return any output. - Is it the case that auditing is not enabled at boot time? - - - - To check if the system login banner is compliant, -run the following command: - -$ cat /etc/issue - Is it the case that it does not display the required banner? - - - - -If the system is configured to prevent the loading of the atm kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the atm kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r atm /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To verify that rsyslog's Forwarding Output Module has CA certificate -configured for its TLS connections to remote server, run the following command: -$ grep DefaultNetstreamDriverCAFile /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should include record similar to -global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem") -where the path to the CA file (/etc/pki/tls/cert.pem in case above) must point to the correct CA certificate. - Is it the case that CA certificate for rsyslog remote logging via TLS is not set? - - - - To verify that the audit system collects unauthorized file accesses, run the following commands: -$ sudo grep EACCES /etc/audit/audit.rules -$ sudo grep EPERM /etc/audit/audit.rules - Is it the case that 32-bit and 64-bit system calls to creat, open, openat, open_by_handle_at, truncate, and ftruncate are not audited during EACCES and EPERM? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules -The output has to be exactly as follows: -## Unsuccessful permission change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change - Is it the case that the file does not exist or the content differs? - - - - The runtime status of the kernel.kexec_load_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.kexec_load_disabled -1. - - Is it the case that the correct value is not returned? - - - - Verify the umask setting is configured correctly in the /etc/bashrc file with the following command: - -$ sudo grep "umask" /etc/bashrc - -umask - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - - - To verify that root's primary group is zero run the following command: - - grep '^root:' /etc/passwd | cut -d : -f 4 - -The command should return: - -0 - - Is it the case that root has a primary gid not equal to zero? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine if the system is configured correctly: -space_left SIZE_in_MB - Is it the case that the system is not configured a specfic size in MB to notify administrators of an issue? - - - - The tftp package can be removed with the following command: $ sudo yum erase tftp - Is it the case that ? - - - - To check which SSH protocol version is allowed, check version of -openssh-server with following command: -$ rpm -qi openssh-server | grep Version -Versions equal to or higher than 7.4 have deprecated the RhostsRSAAuthentication option. -If version is lower than 7.4, run the following command to check configuration: -To determine how the SSH daemon's RhostsRSAAuthentication option is set, run the following command: - -$ sudo grep -i RhostsRSAAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check the permissions of /etc/cron.daily, -run the command: -$ ls -l /etc/cron.daily -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.daily does not have unix mode -rwx------? - - - - The runtime status of the net.ipv4.conf.all.send_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.send_redirects -0. - - Is it the case that the correct value is not returned? - - - - To verify whether audispd plugin off-loads audit records onto a different -system or media from the system being audited, run the following command: - -$ sudo grep -i remote_server /etc/audit/audisp-remote.conf - -The output should return something similar to where REMOTE_SYSTEM -is an IP address or hostname: -remote_server = REMOTE_SYSTEM - -Determine which partition the audit records are being written to with the -following command: - -$ sudo grep log_file /etc/audit/auditd.conf -log_file = /var/log/audit/audit.log - -Check the size of the partition that audit records are written to with the -following command and verify whether it is sufficiently large: - -$ sudo df -h /var/log/audit/ -/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit - Is it the case that audispd is not sending logs to a remote system and the local partition has inadequate space? - - - - Verify the system commands contained in the following directories are group-owned by "root", or a required system account, with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ! -group root -exec ls -l {} \; - Is it the case that any system commands are returned and is not group-owned by a required system account? - - - - Run the following command to determine if the dovecot package is installed: -$ rpm -q dovecot - Is it the case that the package is installed? - - - - To check the permissions of /etc/group, -run the command: -$ ls -l /etc/group -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/group does not have unix mode -rw-r--r--? - - - - To verify that remote access methods are logging to rsyslog, -run the following command: -grep -rE '(auth.\*|authpriv.\*|daemon.\*)' /etc/rsyslog.* -The output should contain auth.*, authpriv.*, and daemon.* -pointing to a log file. - Is it the case that remote access methods are not logging to rsyslog? - - - - System commands are stored in the following directories: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -For each of these directories, run the following command to find directories not -owned by root: -$ sudo find -L $DIR ! -group root -type d -exec chgrp root {} \; - Is it the case that any of these directories are not group owned by root? - - - - To check the ownership of /etc/iptables, -run the command: -$ ls -lL /etc/iptables -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/iptables does not have an owner of root? - - - - The runtime status of the fs.suid_dumpable kernel parameter can be queried -by running the following command: -$ sysctl fs.suid_dumpable -0. - - Is it the case that the correct value is not returned? - - - - -To properly set the group owner of /etc/audit/, run the command: -$ sudo chgrp root /etc/audit/ - -To properly set the group owner of /etc/audit/rules.d/, run the command: -$ sudo chgrp root /etc/audit/rules.d/ - Is it the case that ? - - - - To determine how the SSH daemon's KerberosAuthentication option is set, run the following command: - -$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Verify Oracle Linux 9 disables storing core dumps for all users by issuing the following command: - -$ grep -i storage /etc/systemd/coredump.conf - -Storage=none - Is it the case that Storage is not set to none or is commented out and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? - - - - The runtime status of the net.ipv4.conf.all.route_localnet kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.route_localnet -0. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chage" command with the following command: - -$ sudo auditctl -l | grep chage - --a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chage - Is it the case that the command does not return a line, or the line is commented out? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to disable the -ipv6 kernel module, it will contain a line -of the form: -options ipv6 disable=1 -Such lines may be inside any file in /etc/modprobe.d or the -deprecated/etc/modprobe.conf. This permits insertion of the IPv6 -kernel module (which other parts of the system expect to be present), but -otherwise keeps it inactive. Run the following command to search for such -lines in all files in /etc/modprobe.d and the deprecated -/etc/modprobe.conf: -$ grep -r ipv6 /etc/modprobe.conf /etc/modprobe.d - Is it the case that the ipv6 kernel module is not disabled? - - - - The runtime status of the net.ipv4.ip_local_port_range kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.ip_local_port_range -32768 65535. - - Is it the case that the correct value is not returned? +UnitFileState=masked + Is it the case that service and/or socket are running? @@ -261556,6 +285068,126 @@ rngd service: $ sudo systemctl is-active rngd If the service is running, it should return the following: active Is it the case that the "rngd" service is disabled, masked, or not started.? + + + + To check that the rsyncd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled rsyncd +Output should indicate the rsyncd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled rsyncd disabled + +Run the following command to verify rsyncd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active rsyncd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the rsyncd is masked, run the following command: +$ sudo systemctl show rsyncd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "rsyncd" is loaded and not masked? + + + + + +Run the following command to determine the current status of the +rsyslog service: +$ sudo systemctl is-active rsyslog +If the service is running, it should return the following: active + Is it the case that the "rsyslog" service is disabled, masked, or not started.? + + + + To check that the snmpd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled snmpd +Output should indicate the snmpd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled snmpd disabled + +Run the following command to verify snmpd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active snmpd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the snmpd is masked, run the following command: +$ sudo systemctl show snmpd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "snmpd" is loaded and not masked? + + + + To check that the squid service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled squid +Output should indicate the squid service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled squid disabled + +Run the following command to verify squid is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active squid + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the squid is masked, run the following command: +$ sudo systemctl show squid | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "squid" is loaded and not masked? + + + + To check that the sshd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled sshd +Output should indicate the sshd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled sshd disabled + +Run the following command to verify sshd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active sshd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the sshd is masked, run the following command: +$ sudo systemctl show sshd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "sshd" is loaded and not masked? + + + + + +Run the following command to determine the current status of the +sshd service: +$ sudo systemctl is-active sshd +If the service is running, it should return the following: active + Is it the case that sshd service is disabled? @@ -261568,85 +285200,927 @@ If the service is running, it should return the following: active Is it the case that the service is not enabled? - + -If the system is configured to prevent the loading of the tipc kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. -These lines can also instruct the module loading system to ignore the tipc kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r tipc /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? +Run the following command to determine the current status of the +syslog-ng service: +$ sudo systemctl is-active syslog-ng +If the service is running, it should return the following: active + Is it the case that the "syslog-ng" service is disabled, masked, or not started.? - - Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: + + To verify that acquiring, saving, and processing core dumps is disabled, run the +following command: +$ systemctl status systemd-coredump.socket +The output should be similar to: +● systemd-coredump.socket + Loaded: masked (Reason: Unit systemd-coredump.socket is masked.) + Active: inactive (dead) ... -$ sudo grep audit /etc/security/faillock.conf - -audit - Is it the case that the "audit" option is not set, is missing or commented out? + Is it the case that unit systemd-coredump.socket is not masked or running? - - Verify Oracle Linux 9 is configured to lock an account after -unsuccessful logon attempts with the command: + + -$ grep 'deny =' /etc/security/faillock.conf -deny = . - Is it the case that the "deny" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_deny" />" -or less (but not "0"), is missing or commented out? +Run the following command to determine the current status of the +systemd-journald service: +$ sudo systemctl is-active systemd-journald +If the service is running, it should return the following: active + Is it the case that the systemd-journald service is not running? - - To verify that there are no .shosts files -on the system, run the following command: -$ sudo find / -name '.shosts' - Is it the case that .shosts files exist? + + +To check that the telnet service is disabled in system boot configuration with xinetd, run the following command: +$ chkconfig telnet --list +Output should indicate the telnet service has either not been installed, or has been disabled, as shown in the example below: +$ chkconfig telnet --list + +Note: This output shows SysV services only and does not include native +systemd services. SysV configuration data might be overridden by native +systemd configuration. + +If you want to list systemd services use 'systemctl list-unit-files'. +To see services enabled on particular target use +'systemctl list-dependencies [target]'. + +telnet off + +To check that the telnet socket is disabled in system boot configuration with systemd, run the following command: +$ systemctl is-enabled telnet +Output should indicate the telnet socket has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled telnetdisabled + +Run the following command to verify telnet is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active telnet + +If the socket is not running the command will return the following output: +inactive + +The socket will also be masked, to check that the telnet is masked, run the following command: +$ sudo systemctl show telnet | grep "LoadState\|UnitFileState" + +If the socket is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that service and/or socket are running? - - Verify that Oracle Linux 9 is configured to audit the execution of the "setfacl" command with the following command: + + -$ sudo auditctl -l | grep setfacl - --a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? +Run the following command to determine the current status of the +ufw service: +$ sudo systemctl is-active ufw +If the service is running, it should return the following: active + Is it the case that the service is not enabled? - - The runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter can be queried + + + +Run the following command to determine the current status of the +usbguard service: +$ sudo systemctl is-active usbguard +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + Inspect the file /etc/firewalld/firewalld.conf to determine +the default zone for the firewalld. It should be set to DefaultZone=drop: +$ sudo grep DefaultZone /etc/firewalld/firewalld.conf + Is it the case that the default zone is not set to DROP? + + + + If IPv6 is disabled, this is not applicable. + +Inspect the file /etc/sysconfig/ip6tables to determine +the default policy for the INPUT chain. It should be set to DROP: +$ sudo grep ":INPUT" /etc/sysconfig/ip6tables + Is it the case that the default policy for the INPUT chain is not set to DROP? + + + + Inspect the file /etc/sysconfig/iptables to determine +the default policy for the INPUT chain. It should be set to DROP: +$ sudo grep ":INPUT" /etc/sysconfig/iptables + Is it the case that the default policy for the INPUT chain is not set to DROP? + + + + Run the following command to ensure the default FORWARD policy is DROP: +grep ":FORWARD" /etc/sysconfig/iptables +The output should be similar to the following: +$ sudo grep ":FORWARD" /etc/sysconfig/iptables +:FORWARD DROP [0:0 + Is it the case that the default policy for the FORWARD chain is not set to DROP? + + + + Verify that the libuser is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. + + +Check the hashing algorithm that is being used to hash passwords with the following command: + +$ sudo grep -i crypt_style /etc/libuser.conf + +crypt_style = + Is it the case that crypt_style is not set to sha512? + + + + Verify that the shadow password suite configuration is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. + + +Check the hashing algorithm that is being used to hash passwords with the following command: + +$ sudo grep -i ENCRYPT_METHOD /etc/login.defs + +ENCRYPT_METHOD + Is it the case that ENCRYPT_METHOD is not set to <sub idref="var_password_hashing_algorithm" />? + + + + Inspect the password section of /etc/pam.d/password-auth +and ensure that the pam_unix.so module is configured to use the argument +: + +$ grep /etc/pam.d/password-auth + Is it the case that it does not? + + + + Inspect the password section of /etc/pam.d/system-auth +and ensure that the pam_unix.so module is configured to use the argument +: + +$ sudo grep "^password.*pam_unix\.so.*" /etc/pam.d/system-auth + +password sufficient pam_unix.so + Is it the case that "<sub idref="var_password_hashing_algorithm_pam" />" is missing, or is commented out? + + + + Inspect /etc/login.defs and ensure that if either +SHA_CRYPT_MIN_ROUNDS or SHA_CRYPT_MAX_ROUNDS +are set, they must have the minimum value of . + Is it the case that it does not? + + + + To ensure only SNMPv3 or newer is used, run the following command: +$ sudo grep 'rocommunity\|rwcommunity\|com2sec' /etc/snmp/snmpd.conf | grep -v "^#" +There should be no output. + Is it the case that there is output? + + + + To check if RekeyLimit is set correctly, run the following command: +$ sudo grep RekeyLimit /etc/ssh/ssh_config.d/*.conf +If configured properly, output should be +/etc/ssh/ssh_config.d/02-rekey-limit.conf: +RekeyLimit +Check also the main configuration file with the following command: +$ sudo grep RekeyLimit /etc/ssh/ssh_config +The command should not return any output. + Is it the case that it is commented out or is not set? + + + + For each private key stored on the system, use the following command: +$ sudo ssh-keygen -y -f /path/to/file +If the contents of the key are displayed, this is a finding. + Is it the case that no ssh private key is accessible without a passcode? + + + + To check which SSH protocol version is allowed, check version of openssh-server with following command: + +$ rpm -qi openssh-server | grep Version + +Versions equal to or higher than 7.4 only allow Protocol 2. +If version is lower than 7.4, run the following command to check configuration: +$ sudo grep Protocol /etc/ssh/sshd_config +If configured properly, output should be Protocol 2 + Is it the case that it is commented out or is not set correctly to Protocol 2? + + + + To check if compression is enabled or set correctly, run the +following command: +$ sudo grep Compression /etc/ssh/sshd_config +If configured properly, output should be no or delayed. + Is it the case that it is commented out, or is not set to no or delayed? + + + + To determine how the SSH daemon's PermitEmptyPasswords option is set, run the following command: + +$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's KerberosAuthentication option is set, run the following command: + +$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: + +$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's IgnoreRhosts option is set, run the following command: + +$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check which SSH protocol version is allowed, check version of +openssh-server with following command: +$ rpm -qi openssh-server | grep Version +Versions equal to or higher than 7.4 have deprecated the RhostsRSAAuthentication option. +If version is lower than 7.4, run the following command to check configuration: +To determine how the SSH daemon's RhostsRSAAuthentication option is set, run the following command: + +$ sudo grep -i RhostsRSAAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PermitRootLogin option is set, run the following command: + +$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PermitRootLogin option is set, run the following command: + +$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating prohibit-password is returned, then the required value is set. + Is it the case that it is commented out or not configured properly? + + + + To determine how the SSH daemon's AllowTcpForwarding option is set, run the following command: + +$ sudo grep -i AllowTcpForwarding /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + Is it the case that The AllowTcpForwarding option exists and is disabled? + + + + To determine how the SSH daemon's IgnoreUserKnownHosts option is set, run the following command: + +$ sudo grep -i IgnoreUserKnownHosts /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's X11Forwarding option is set, run the following command: + +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PermitUserEnvironment option is set, run the following command: + +$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's UsePAM option is set, run the following command: + +$ sudo grep -i UsePAM /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: + +$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's StrictModes option is set, run the following command: + +$ sudo grep -i StrictModes /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i StrictModes /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's Banner option is set, run the following command: + +$ sudo grep -i Banner /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating /etc/issue is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's Banner option is set, run the following command: + +$ sudo grep -i Banner /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating /etc/issue.net is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's X11Forwarding option is set, run the following command: + +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To ensure sshd limits the users who can log in, run the following: +$ sudo grep -rPi '^\h*(allow|deny)(users|groups)\h+\H+(\h+.*)?$' /etc/ssh/sshd_config* +If properly configured, the output should be a list of usernames and/or +groups allowed to log in to this system. + Is it the case that sshd does not limit the users who can log in? + + + + To determine how the SSH daemon's PrintLastLog option is set, run the following command: + +$ sudo grep -i PrintLastLog /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i PrintLastLog /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check if RekeyLimit is set correctly, run the +following command: + +$ sudo grep RekeyLimit /etc/ssh/sshd_config /etc/ssh/sshd_config.d/* + +If configured properly, output should be +RekeyLimit + Is it the case that it is commented out or is not set? + + + + Run the following command to see what the timeout interval is: +$ sudo grep ClientAliveInterval /etc/ssh/sshd_config +If properly configured, the output should be: +ClientAliveInterval + Is it the case that it is commented out or not configured properly? + + + + To ensure ClientAliveInterval is set correctly, run the following command: +$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config +If properly configured, the output should be: +ClientAliveCountMax +For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when +the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout +functionality completely. +If the option is set to a number greater than 0, then the session will be disconnected after +ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message. + Is it the case that it is commented out or not configured properly? + + + + To ensure ClientAliveInterval is set correctly, run the following command: + +$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf + +If properly configured, the output should be: +ClientAliveCountMax 0 + +In this case, the SSH timeout occurs precisely when +the ClientAliveInterval is set. + Is it the case that it is commented out or not configured properly? + + + + To ensure LoginGraceTime is set correctly, run the following command: +$ sudo grep LoginGraceTime /etc/ssh/sshd_config +If properly configured, the output should be: +LoginGraceTime +If the option is set to a number greater than 0, then the unauthenticated session will be disconnected +after the configured number seconds. + Is it the case that it is commented out or not configured properly? + + + + To determine how the SSH daemon's LogLevel option is set, run the following command: + +$ sudo grep -i LogLevel /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i LogLevel /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating INFO is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's LogLevel option is set, run the following command: + +$ sudo grep -i LogLevel /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating VERBOSE is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To ensure the MaxAuthTries parameter is set, run the following command: +$ sudo grep MaxAuthTries /etc/ssh/sshd_config +If properly configured, output should be: +MaxAuthTries + Is it the case that it is commented out or not configured properly? + + + + Run the following command to see what the max sessions number is: +$ sudo grep MaxSessions /etc/ssh/sshd_config +If properly configured, the output should be: +MaxSessions + Is it the case that MaxSessions is not configured or not configured correctly? + + + + To check if MaxStartups is configured, run the following command: +$ sudo grep -r ^[\s]*MaxStartups /etc/ssh/sshd_config* +If configured, this command should output the configuration. + Is it the case that maxstartups is not configured? + + + + To determine whether the SSH server includes configuration files from the right directory, run the following command: +$ sudo grep -i '^Include' /etc/ssh/sshd_config +If a line Include /etc/ssh/sshd_config.d/*.conf is returned, then the configuration file inclusion is set correctly. + Is it the case that you don't include other configuration files from the main configuration file? + + + + To check if UsePrivilegeSeparation is enabled or set correctly, run the +following command: +$ sudo grep UsePrivilegeSeparation /etc/ssh/sshd_config +If configured properly, output should be . + Is it the case that it is commented out or is not enabled? + + + + To determine how the SSH daemon's X11UseLocalhost option is set, run the following command: + +$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + Is it the case that the display proxy is listening on wildcard address? + + + + Check to see if Online Certificate Status Protocol (OCSP) +is enabled and using the proper digest value on the system with the following command: +$ sudo grep certificate_verification /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf | grep -v "^#" +If configured properly, output should look like + + certificate_verification = ocsp_dgst= + + Is it the case that certificate_verification in sssd is not configured? + + + + To verify Certmap is enabled in SSSD, run the following command: +$ sudo cat /etc/sssd/sssd.conf +If configured properly, output should contain section like the following + +[certmap/testing.test/rule_name] +matchrule =<SAN>.*EDIPI@mil +maprule = (userCertificate;binary={cert!bin}) +domains = testing.test + + Is it the case that Certmap is not configured in SSSD? + + + + To verify that SSSD is configured for PAM services, run the following command: +$ sudo grep services /etc/sssd/sssd.conf +If configured properly, output should be similar to +services = pam + Is it the case that it does not exist or 'pam' is not added to the 'services' option under the 'sssd' section? + + + + To verify that smart cards are enabled in SSSD, run the following command: +$ sudo grep pam_cert_auth /etc/sssd/sssd.conf +If configured properly, output should be +pam_cert_auth = True + + +To verify that smart cards are enabled in PAM files, run the following command: +$ sudo grep -e "auth.*pam_sss\.so.*\(allow_missing_name\|try_cert_auth\)" /etc/pam.d/smartcard-auth /etc/pam.d/system-auth +If configured properly, output should be + +/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name +/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth + + Is it the case that smart cards are not enabled in SSSD? + + + + Verify Oracle Linux 9 for PKI-based authentication has valid certificates by constructing a +certification path (which includes status information) to an accepted trust anchor. + +Check that the system has a valid DoD root CA installed with the following command: + +$ sudo openssl x509 -text -in /etc/sssd/pki/sssd_auth_ca_db.pem + +Certificate: +Data: +Version: 3 (0x2) +Serial Number: 1 (0x1) +Signature Algorithm: sha256WithRSAEncryption +Issuer: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 +Validity +Not Before: Mar 20 18:46:41 2012 GMT +Not After : Dec 30 18:46:41 2029 GMT +Subject: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 +Subject Public Key Info: +Public Key Algorithm: rsaEncryption + Is it the case that root CA file is not a DoD-issued certificate with a valid date and installed in the /etc/sssd/pki/sssd_auth_ca_db.pem location? + + + + To verify the LDAP client backend demands a valid certificate from the server in +remote LDAP access sessions, run the following command: +$ sudo grep ldap_tls_reqcert /etc/sssd/sssd.conf +The output should return the following: +ldap_tls_reqcert = demand + Is it the case that the TLS reqcert is not set to demand? + + + + If the system is not using TLS, set the ldap_id_use_start_tls option +in /etc/sssd/sssd.conf to true. + Is it the case that the 'ldap_id_use_start_tls' option is not set to 'true'? + + + + +Check if SSSD allows cached authentications with the following command: + +$ sudo grep cache_credentials /etc/sssd/sssd.conf +cache_credentials = true + +If "cache_credentials" is set to "false" or is missing no further checks are required. + +To verify that SSSD expires offline credentials, run the following command: +$ sudo grep offline_credentials_expiration /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf +If configured properly, output should be +offline_credentials_expiration = 1 + Is it the case that it does not exist or is not configured properly? + + + + To determine if NOEXEC has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\bnoexec\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that noexec is not enabled in sudo? + + + + To determine if requiretty has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\brequiretty\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that requiretty is not enabled in sudo? + + + + To determine if use_pty has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\buse_pty\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that use_pty is not enabled in sudo? + + + + To determine if logfile has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults\s*\blogfile\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that logfile is not enabled in sudo? + + + + To check the group ownership of /usr/bin/sudo, +run the command: +$ ls -lL /usr/bin/sudo +If properly configured, the output should indicate the following group-owner: + + + + Is it the case that /usr/bin/sudo does not have a group owner of +<sub idref="var_sudo_dedicated_group" /> +? + + + + To determine if !authenticate has not been configured for sudo, run the following command: +$ sudo grep -r \!authenticate /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that !authenticate is specified in the sudo config files? + + + + To determine if NOPASSWD has been configured for sudo, run the following command: +$ sudo grep -ri nopasswd /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that nopasswd is specified in the sudo config files? + + + + To determine if NOPASSWD or !authenticate have been configured for +sudo, run the following command: +$ sudo grep -ri "nopasswd\|\!authenticate" /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that nopasswd and/or !authenticate is enabled in sudo? + + + + Verify the operating system requires re-authentication +when using the "sudo" command to elevate privileges, run the following command: +sudo grep -ri '^Defaults.*timestamp_timeout' /etc/sudoers /etc/sudoers.d +The output should be: +/etc/sudoers:Defaults timestamp_timeout=0 or "timestamp_timeout" is set to a positive number. +If conflicting results are returned, this is a finding. + Is it the case that timestamp_timeout is not set with the appropriate value for sudo? + + + + Determine if "sudoers" file restricts sudo access run the following commands: +$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* +$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* + Is it the case that either of the commands returned a line? + + + + To determine if NOPASSWD has been configured for the vdsm user for sudo, +run the following command: +$ sudo grep -ri nopasswd /etc/sudoers.d/ +The command should return output only for the vdsm user. + Is it the case that nopasswd is set for any users beyond vdsm? + + + + To determine if arguments that commands can be executed with are restricted, run the following command: +$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$))' /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that /etc/sudoers file contains user specifications that allow execution of commands with any arguments? + + + + To determine if negation is used to define commands users are allowed to execute using sudo, run the following command: +$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).*' /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that /etc/sudoers file contains rules that define the set of allowed commands using negation? + + + + To determine if the users are allowed to run commands as root, run the following commands: +$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s]' /etc/sudoers /etc/sudoers.d/ +and +$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\)' /etc/sudoers /etc/sudoers.d/ +Both commands should return no output. + Is it the case that /etc/sudoers file contains rules that allow non-root users to run commands as root? + + + + Run the following command to Verify that the sudoers security policy is configured to use the invoking user's password for privilege escalation: + sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)' +or if cvtsudoers not supported: + sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; +If no results are returned, this is a finding. +If conflicting results are returned, this is a finding. +If "Defaults !targetpw" is not defined, this is a finding. +If "Defaults !rootpw" is not defined, this is a finding. +If "Defaults !runaspw" is not defined, this is a finding. + Is it the case that invoke user passwd when using sudo? + + + + To verify that kernel parameter 'crypto.fips_enabled' is set properly, run the following command: +sysctl crypto.fips_enabled +The output should contain the following: +crypto.fips_enabled = 1 + Is it the case that crypto.fips_enabled is not 1? + + + + The runtime status of the fs.protected_fifos kernel parameter can be queried by running the following command: -$ sysctl net.ipv4.icmp_echo_ignore_broadcasts +$ sysctl fs.protected_fifos +2. + + Is it the case that the correct value is not returned? + + + + The runtime status of the fs.protected_hardlinks kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_hardlinks 1. Is it the case that the correct value is not returned? - - Verify Oracle Linux 9 disables core dump backtraces by issuing the following command: + + The runtime status of the fs.protected_regular kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_regular +2. -$ grep -i process /etc/systemd/coredump.conf - -ProcessSizeMax=0 - Is it the case that the "ProcessSizeMax" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + Is it the case that the correct value is not returned? - - To determine if the system is configured to make login UIDs immutable, run -one of the following commands. -If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), run the following: -sudo grep immutable /etc/audit/rules.d/*.rules -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, run the following command: -sudo grep immutable /etc/audit/audit.rules -The following line should be returned: ---loginuid-immutable - Is it the case that the system is not configured to make login UIDs immutable? + + The runtime status of the fs.protected_symlinks kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_symlinks +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the fs.suid_dumpable kernel parameter can be queried +by running the following command: +$ sysctl fs.suid_dumpable +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.core_pattern kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_pattern +|/bin/false. + + Is it the case that the returned line does not have a value of "|/bin/false", or a line is not +returned and the need for core dumps is not documented with the Information +System Security Officer (ISSO) as an operational requirement? + + + + The runtime status of the kernel.core_pattern kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_pattern | cat -A +kernel.core_pattern = $ + + Is it the case that the returned line does not have an empty string? + + + + The runtime status of the kernel.core_uses_pid kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_uses_pid +0. + Is it the case that the returned line does not have a value of 0? + + + + The runtime status of the kernel.dmesg_restrict kernel parameter can be queried +by running the following command: +$ sysctl kernel.dmesg_restrict +1. + + Is it the case that the correct value is not returned? + + + + To verify ExecShield is enabled on 64-bit Oracle Linux 9 systems, +run the following command: +$ dmesg | grep '[NX|DX]*protection' +The output should not contain 'disabled by kernel command line option'. +Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes noexec=off, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*noexec=off.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*noexec=off.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'noexec=off' +The command should not return any output. + Is it the case that ExecShield is not supported by the hardware, is not enabled, or has been disabled by the kernel configuration.? + + + + The runtime status of the kernel.kexec_load_disabled kernel parameter can be queried +by running the following command: +$ sysctl kernel.kexec_load_disabled +1. + + Is it the case that the correct value is not returned? @@ -261676,168 +286150,211 @@ Conflicting assignments are not allowed. Is it the case that the kernel.kptr_restrict is not set to 1 or 2 or is configured to be 0? - - To determine how the SSH daemon's StrictModes option is set, run the following command: - -$ sudo grep -i StrictModes /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check the ownership of /etc/cron.deny, -run the command: -$ ls -lL /etc/cron.deny -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.deny does not have an owner of root? - - - - The runtime status of the net.ipv4.conf.all.shared_media kernel parameter can be queried + + The runtime status of the kernel.modules_disabled kernel parameter can be queried by running the following command: -$ sysctl net.ipv4.conf.all.shared_media -0. - - Is it the case that the correct value is not returned? - - - - To check the password warning age, run the command: -$ grep PASS_WARN_AGE /etc/login.defs -The DoD requirement is 7. - Is it the case that it is not set to the required value? - - - - To verify the sec option is configured for all NFS mounts, run the following command: -$ grep "sec=" /etc/exports -All configured NFS exports should show the sec=krb5:krb5i:krb5p setting in parentheses. -This is not applicable if NFS is not implemented. - Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? - - - - To check the group ownership of /etc/passwd-, -run the command: -$ ls -lL /etc/passwd- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/passwd- does not have a group owner of root? - - - - The runtime status of the net.ipv4.tcp_rfc1337 kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.tcp_rfc1337 +$ sysctl kernel.modules_disabled 1. Is it the case that the correct value is not returned? - - To verify the nodev option is configured for all NFS mounts, run -the following command: -$ mount | grep nfs -All NFS mounts should show the nodev setting in parentheses. This -is not applicable if NFS is not implemented. - Is it the case that the setting does not show? - - - - To determine whether yum has been configured to disable -gpgcheck for any repos, inspect all files in -/etc/yum.repos.d and ensure the following does not appear in any -sections: -gpgcheck=0 -A value of 0 indicates that gpgcheck has been disabled for that repo. - Is it the case that GPG checking is disabled? - - - - To determine if requiretty has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\brequiretty\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that requiretty is not enabled in sudo? - - - - -Run the following command to get the current configured value for deny_execmem -SELinux boolean: -$ getsebool deny_execmem -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that deny_execmem is not set as expected? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the truncate system call. + + The runtime status of the kernel.panic_on_oops kernel parameter can be queried +by running the following command: +$ sysctl kernel.panic_on_oops +1. -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r truncate /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep truncate /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? + Is it the case that the correct value is not returned? - - To ensure the system is configured to ignore the Ctrl-Alt-Del sequence, -run the following command: -$ gsettings get org.gnome.settings-daemon.plugins.media-keys logout -$ grep logout /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/settings-daemon/plugins/media-keys/logout - Is it the case that GNOME3 is configured to reboot when Ctrl-Alt-Del is pressed? - - - - The following command will list which files on the system have permissions different from what -is expected by the RPM database: -$ rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' - Is it the case that there is output? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "sudo" command with the following command: + + The runtime status of the kernel.perf_cpu_time_max_percent kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_cpu_time_max_percent +1. -$ sudo auditctl -l | grep sudo + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.perf_event_max_sample_rate kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_event_max_sample_rate +1. --a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudo - Is it the case that the command does not return a line, or the line is commented out? + Is it the case that the correct value is not returned? - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes mce=0, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mce=0.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*mce=0.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'mce=0' -The command should not return any output. - Is it the case that MCE tolerance is not set to zero? + + The runtime status of the kernel.perf_event_paranoid kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_event_paranoid +2. + + Is it the case that the correct value is not returned? - - Run the following command to determine if the rng-tools package is installed: $ rpm -q rng-tools - Is it the case that the package is not installed? + + The runtime status of the kernel.pid_max kernel parameter can be queried +by running the following command: +$ sysctl kernel.pid_max +65536. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.randomize_va_space kernel parameter can be queried +by running the following command: +$ sysctl kernel.randomize_va_space +2. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.sysrq kernel parameter can be queried +by running the following command: +$ sysctl kernel.sysrq +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.unprivileged_bpf_disabled kernel parameter can be queried +by running the following command: +$ sysctl kernel.unprivileged_bpf_disabled +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.unprivileged_bpf_disabled +kernel parameter can be queried by running the following command: +$ sysctl kernel.unprivileged_bpf_disabled +The output of the command should indicate either: +kernel.unprivileged_bpf_disabled = 1 +or: +kernel.unprivileged_bpf_disabled = 2 +The output of the command should not indicate: +kernel.unprivileged_bpf_disabled = 0 + +The preferable way how to assure the runtime compliance is to have +correct persistent configuration, and rebooting the system. + +The persistent kernel parameter configuration is performed by specifying the appropriate +assignment in any file located in the /etc/sysctl.d directory. +Verify that there is not any existing incorrect configuration by executing the following command: +$ grep -r '^\s*\s*=' /etc/sysctl.conf /etc/sysctl.d +The command should not find any assignments other than: +kernel.unprivileged_bpf_disabled = 1 +or: +kernel.unprivileged_bpf_disabled = 2 + +Duplicate assignments are not allowed. Empty output is allowed, because the system default is 2. + Is it the case that the kernel.unprivileged_bpf_disabled is not set to 1 or 2 or is configured to be 0? + + + + The runtime status of the kernel.yama.ptrace_scope kernel parameter can be queried +by running the following command: +$ sysctl kernel.yama.ptrace_scope +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.core.bpf_jit_harden kernel parameter can be queried +by running the following command: +$ sysctl net.core.bpf_jit_harden +2. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.accept_local kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_local +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.arp_filter kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.arp_filter +. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.arp_ignore +. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.drop_gratuitous_arp +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.forwarding kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.forwarding +0. +The ability to forward packets is only appropriate for routers. + Is it the case that IP forwarding value is "1" and the system is not router? + + + + The runtime status of the net.ipv4.conf.all.log_martians kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.log_martians +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.route_localnet kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.route_localnet +0. + + Is it the case that the correct value is not returned? @@ -261846,8 +286363,7 @@ by running the following command: $ sysctl net.ipv4.conf.all.rp_filter The output of the command should indicate either: net.ipv4.conf.all.rp_filter = 1 -or: -net.ipv4.conf.all.rp_filter = 2 + The output of the command should not indicate: net.ipv4.conf.all.rp_filter = 0 @@ -261860,756 +286376,37 @@ Verify that there is not any existing incorrect configuration by executing the f $ grep -r '^\s*net.ipv4.conf.all.rp_filter\s*=' /etc/sysctl.conf /etc/sysctl.d The command should not find any assignments other than: net.ipv4.conf.all.rp_filter = 1 -or: -net.ipv4.conf.all.rp_filter = 2 + Conflicting assignments are not allowed. - Is it the case that the net.ipv4.conf.all.rp_filter is not set to 1 or 2 or is configured to be 0? + Is it the case that the net.ipv4.conf.all.rp_filter is not set to 1 or is configured to be 0 or 2? - - To determine how the SSH daemon's IgnoreRhosts option is set, run the following command: - -$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Run the following command to ensure the TMOUT value is configured for all users -on the system: - -$ sudo grep TMOUT /etc/profile /etc/profile.d/*.sh - -The output should return the following: -TMOUT= - Is it the case that value of TMOUT is not less than or equal to expected setting? - - - - To determine how the SSH daemon's LogLevel option is set, run the following command: - -$ sudo grep -i LogLevel /etc/ssh/sshd_config - -If a line indicating INFO is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules -The output has to be exactly as follows: -## Successful ownership change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change - Is it the case that the file does not exist or the content differs? - - - - To determine whether the SSH server includes configuration files from the right directory, run the following command: -$ sudo grep -i '^Include' /etc/ssh/sshd_config -If a line Include /etc/ssh/sshd_config.d/*.conf is returned, then the configuration file inclusion is set correctly. - Is it the case that you don't include other configuration files from the main configuration file? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/security/opasswd)' - --w /etc/security/opasswd -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the permissions of /etc/sestatus.conf, -run the command: -$ ls -l /etc/sestatus.conf -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/sestatus.conf does not have unix mode 0644? - - - - To determine that AIDE is verifying extended file attributes, run the following command: -$ grep xattrs /etc/aide.conf -Verify that the xattrs option is added to the correct ruleset. - Is it the case that the xattrs option is missing or not added to the correct ruleset? - - - - Verify that Oracle Linux 9 has configured the minimum time period between password changes for each user account is one day or greater with the following command: - -$ sudo awk -F: '$4 < 1 {print $1 " " $4}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - Verify that the SA and ISSO (at a minimum) are notified when the audit storage volume is full. - -Check which action Oracle Linux 9 takes when the audit storage volume is full with the following command: - -$ sudo grep max_log_file_action /etc/audit/auditd.conf -max_log_file_action = - Is it the case that the value of the "max_log_file_action" option is set to "ignore", "rotate", or "suspend", or the line is commented out? - - - - To verify that cryptography policy has been configured correctly, run the -following command: -$ update-crypto-policies --show -The output should return . -Run the command to check if the policy is correctly applied: -$ update-crypto-policies --is-applied -The output should be The configured policy is applied. -Moreover, check if settings for selected crypto policy are as expected. -List all libraries for which it holds that their crypto policies do not have symbolic link in /etc/crypto-policies/back-ends. -$ ls -l /etc/crypto-policies/back-ends/ | grep '^[^l]' | tail -n +2 | awk -F' ' '{print $NF}' | awk -F'.' '{print $1}' | sort -Subsequently, check if matching libraries have drop in files in the /etc/crypto-policies/local.d directory. -$ ls /etc/crypto-policies/local.d/ | awk -F'-' '{print $1}' | uniq | sort -Outputs of two previous commands should match. - Is it the case that cryptographic policy is not configured or is configured incorrectly? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/lastlog" with the following command: - -$ sudo auditctl -l | grep /var/log/lastlog - --w /var/log/lastlog -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes iommu=force, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*iommu=force.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*iommu=force.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'iommu=force' -The command should not return any output. - Is it the case that I/OMMU is not activated? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEVKMEM /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command and verify that time sources are only configured with server directive: -# grep -E "^(server|pool)" /etc/chrony.conf -A line with the appropriate server should be returned, any line returned starting with pool is a finding. - Is it the case that an authoritative remote time server is not configured or configured with pool directive? - - - - To check the permissions of /var/log/messages, -run the command: -$ ls -l /var/log/messages -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /var/log/messages does not have unix mode -rw-------? - - - - Verify Oracle Linux 9 enforces 24 hours/one day as the minimum password lifetime for new user accounts. - -Check for the value of "PASS_MIN_DAYS" in "/etc/login.defs" with the following command: - -$ grep -i pass_min_days /etc/login.defs - -PASS_MIN_DAYS - Is it the case that the "PASS_MIN_DAYS" parameter value is not "<sub idref="var_accounts_minimum_age_login_defs" />" or greater, or is commented out? - - - - Run the following command to determine if the libreswan package is installed: $ rpm -q libreswan - Is it the case that the package is not installed? - - - - Ensure that debug-shell service is not enabled with the following command: -grep systemd\.debug-shell=1 /boot/grub2/grubenv /etc/default/grub -If the command returns a line, it means that debug-shell service is being enabled. - Is it the case that the comand returns a line? - - - - Using a non-privileged account, verify that users cannot modify or change -network settings with the nmcli command with the following command: -$ nmcli general permissions -The output should contain the following: -PERMISSION VALUE -org.freedesktop.NetworkManager.enable-disable-network auth -org.freedesktop.NetworkManager.enable-disable-wifi auth -org.freedesktop.NetworkManager.enable-disable-wwan auth -org.freedesktop.NetworkManager.enable-disable-wimax auth -org.freedesktop.NetworkManager.sleep-wake auth -org.freedesktop.NetworkManager.network-control auth -org.freedesktop.NetworkManager.wifi.share.protected auth -org.freedesktop.NetworkManager.wifi.share.open auth -org.freedesktop.NetworkManager.settings.modify.system auth -org.freedesktop.NetworkManager.settings.modify.own auth -org.freedesktop.NetworkManager.settings.modify.hostname auth -org.freedesktop.NetworkManager.settings.modify.global-dns auth -org.freedesktop.NetworkManager.reload auth -org.freedesktop.NetworkManager.checkpoint-rollback auth -org.freedesktop.NetworkManager.enable-disable-statistics auth -org.freedesktop.NetworkManager.enable-disable-connectivity-check auth -org.freedesktop.NetworkManager.wifi.scan auth - - Is it the case that non-privileged users can modify or change network settings? - - - - Verify the nodev option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . nodev . . . - - Is it the case that the "/boot" file system does not have the "nodev" option set? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one numeric character be used. - -Check the value for "dcredit" with the following command: - -$ sudo grep dcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:dcredit = - Is it the case that the value of "dcredit" is a positive number or is commented out? - - - - To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: - -$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - The runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter can be queried + + The runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter can be queried by running the following command: -$ sysctl net.ipv4.conf.default.secure_redirects +$ sysctl net.ipv4.conf.all.secure_redirects 0. Is it the case that the correct value is not returned? - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/10-base-config.rules -The output has to be exactly as follows: -## First rule - delete all --D - -## Increase the buffers to survive stress events. -## Make this bigger for busy systems --b 8192 - -## This determine how long to wait in burst of events ---backlog_wait_time 60000 - -## Set failure mode to syslog --f 1 - Is it the case that the file does not exist or the content differs? - - - - Verify the nodev option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . nodev . . . - - Is it the case that the "/home" file system does not have the "nodev" option set? - - - - To check the status of the idle screen lock activation, run the following command: - -$ gsettings get org.gnome.desktop.screensaver lock-enabled -If properly configured, the output should be true. -To ensure that users cannot change how long until the screensaver locks, run the following: -$ grep lock-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled - Is it the case that screensaver locking is not enabled and/or has not been set or configured correctly? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes page_poison=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_poison=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*page_poison=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'page_poison=1' -The command should not return any output. - Is it the case that page allocator poisoning is not enabled? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "sudoedit" command with the following command: - -$ sudo auditctl -l | grep sudoedit - --a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudoedit - Is it the case that the command does not return a line, or the line is commented out? - - - - -If the system is configured to prevent the loading of the sctp kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the sctp kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r sctp /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To verify that auditing is configured for system administrator actions, run the following command: -$ sudo auditctl -l | grep "watch=/etc/sudoers\|watch=/etc/sudoers.d\|-w /etc/sudoers\|-w /etc/sudoers.d" - Is it the case that there is not output? - - - - To determine if the system is configured to audit calls to the -fchownat system call, run the following command: -$ sudo grep "fchownat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the ownership of /etc/cron.d, -run the command: -$ ls -lL /etc/cron.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.d does not have an owner of root? - - - - Run the following command and verify remote server is configured properly: -# grep -E "^(server|pool)" /etc/chrony.conf - Is it the case that a remote time server is not configured? - - - - To verify all files and directories in interactive user home directory are -group-owned by a group the user is a member of, run the -following command: -$ sudo ls -lLR /home/USER - Is it the case that the group ownership is incorrect? - - - - If the system does not have SELinux enabled and enforcing a targeted policy, or if the -pam_faillock.so module is not configured for use, this requirement is not applicable. - -Verify the location of the non-default tally directory for the pam_faillock.so module with -the following command: - -$ sudo grep -w dir /etc/security/faillock.conf - -dir = /var/log/faillock - -Check the security context type of the non-default tally directory with the following command: - -$ sudo ls -Zd /var/log/faillock - -unconfined_u:object_r:faillog_t:s0 /var/log/faillock - Is it the case that the security context type of the non-default tally directory is not "faillog_t"? - - - - To check the ownership of /etc/shells, -run the command: -$ ls -lL /etc/shells -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shells does not have an owner of root? - - - - Verify that the interactive user account passwords are using a strong -password hash with the following command: - -$ sudo cut -d: -f2 /etc/shadow - -$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/ - -Password hashes ! or * indicate inactive accounts not -available for logon and are not evaluated. - Is it the case that any interactive user password hash does not begin with "$6"? - - - - To verify that automatic logins are disabled, run the following command: -$ grep -Pzoi "^\[daemon]\\nautomaticlogin.*" /etc/gdm/custom.conf -The output should show the following: -[daemon] -AutomaticLoginEnable=false - Is it the case that GDM allows users to automatically login? - - - - Verify that Oracle Linux 9 enforces a -day maximum password lifetime for new user accounts by running the following command: - -$ grep -i pass_max_days /etc/login.defs - -PASS_MAX_DAYS - Is it the case that the "PASS_MAX_DAYS" parameter value is greater than "<sub idref="var_accounts_maximum_age_login_defs" />", or commented out? - - - - To determine if the system is configured to audit calls to the -fchmodat system call, run the following command: -$ sudo grep "fchmodat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if negation is used to define commands users are allowed to execute using sudo, run the following command: -$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).*' /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that /etc/sudoers file contains rules that define the set of allowed commands using negation? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLUB_DEBUG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Inspect /etc/default/grub for any instances of -systemd.confirm_spawn=(1|yes|true|on) in the kernel boot arguments. -Presence of a systemd.confirm_spawn=(1|yes|true|on) indicates -that interactive boot is enabled at boot time and verify that -GRUB_DISABLE_RECOVERY=true to disable recovery boot. - Is it the case that Interactive boot is enabled at boot time? - - - - To check the permissions of /boot/grub2/user.cfg, -run the command: -$ ls -l /boot/grub2/user.cfg -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? - - - - To check the permissions of /etc/shadow, -run the command: -$ ls -l /etc/shadow -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/shadow does not have unix mode ----------? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules -The output has to be exactly as follows: -## Successful file delete --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete --a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete - Is it the case that the file does not exist or the content differs? - - - - Run the following command to determine if the iprutils package is installed: -$ rpm -q iprutils - Is it the case that the package is installed? - - - - The runtime status of the kernel.perf_event_max_sample_rate kernel parameter can be queried + + The runtime status of the net.ipv4.conf.all.send_redirects kernel parameter can be queried by running the following command: -$ sysctl kernel.perf_event_max_sample_rate -1. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 loads the driver with the following command: - -$ grep card_drivers /etc/opensc.conf - -card_drivers = ; - Is it the case that "<sub idref="var_smartcard_drivers" />" is not listed as a card driver, or there is no line returned for "card_drivers"? - - - - The runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_source_route +$ sysctl net.ipv4.conf.all.send_redirects 0. Is it the case that the correct value is not returned? - - Verify that Oracle Linux 9 's INACTIVE conforms to site policy (no more than 30 days) with the following command: + + The runtime status of the net.ipv4.conf.all.shared_media kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.shared_media +0. -$ sudo awk -F: '$7 > 30 {print $1 " " $7}' /etc/shadow - Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_FS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/grub.cfg does not have an owner of root? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "restorecon" command with the following command: - -$ sudo auditctl -l | grep restorecon - --a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -k privileged-restorecon - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the ftruncate system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r ftruncate /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep ftruncate /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the setroubleshoot-plugins package is installed: -$ rpm -q setroubleshoot-plugins - Is it the case that the package is installed? - - - - -If the system is configured to prevent the loading of the dccp kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the dccp kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r dccp /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Verify all local interactive users on Oracle Linux 9 are assigned a home -directory upon creation with the following command: -$ grep -i create_home /etc/login.defs -CREATE_HOME yes - Is it the case that the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out? - - - - To ensure the MaxAuthTries parameter is set, run the following command: -$ sudo grep MaxAuthTries /etc/ssh/sshd_config -If properly configured, output should be: -MaxAuthTries - Is it the case that it is commented out or not configured properly? - - - - Verify file systems that are used for removable media are mounted with the "nodev" option with the following command: - -$ sudo more /etc/fstab - -UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 - Is it the case that a file system found in "/etc/fstab" refers to removable media and it does not have the "nodev" option set? - - - - To verify the local initialization files of all local interactive users are group- -owned by the appropriate user, inspect the primary group of the respective -users in /etc/passwd and verify all initialization files under the -respective users home directory. Check the group owner of all local interactive users -initialization files. - Is it the case that they are not? - - - - To check the ownership of /etc/nftables, -run the command: -$ ls -lL /etc/nftables -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/nftables does not have an owner of root? - - - - To check the ownership of /etc/shadow-, -run the command: -$ ls -lL /etc/shadow- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shadow- does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING_ZERO /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if pam_pwquality.so is enabled in system-auth, run the following command: -$ grep pam_pwquality /etc/pam.d/system-auth -The output should be similar to the following: -password requisite pam_pwquality.so - Is it the case that pam_pwquality.so is not enabled in system-auth? - - - - Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . - - -Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: -$ grep retry /etc/security/pwquality.conf - Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? - - - - -Run the following command to determine if the authlogin_radius SELinux boolean is disabled: -$ getsebool authlogin_radius -If properly configured, the output should show the following: -authlogin_radius --> off - Is it the case that authlogin_radius is not disabled? - - - - To check the ownership of /etc/sysctl.d, -run the command: -$ ls -lL /etc/sysctl.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sysctl.d does not have an owner of root? - - - - Verify the Oracle Linux 9 "fapolicyd" employs a deny-all, permit-by-exception policy. - -Check that "fapolicyd" is in enforcement mode with the following command: - -$ sudo grep permissive /etc/fapolicyd/fapolicyd.conf - -permissive = 0 - -Check that fapolicyd employs a deny-all policy on system mounts with the following commands: -$ sudo tail /etc/fapolicyd/compiled.rules - -allow exe=/usr/bin/python3.7 : ftype=text/x-python -deny_audit perm=any pattern=ld_so : all -deny perm=any all : all - Is it the case that fapolicyd is not running in enforcement mode with a deny-all, permit-by-exception policy? - - - - Verify the nosuid option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . nosuid . . . - - Is it the case that the "/var/log" file system does not have the "nosuid" option set? - - - - Verify that a separate file system/partition has been created for /home with the following command: - -$ mountpoint /home - - Is it the case that "/home is not a mountpoint" is returned? - - - - To verify the sec option is configured for all NFS mounts, run the following command: -$ mount | grep "sec=" -All NFS mounts should show the sec=krb5:krb5i:krb5p setting in parentheses. -This is not applicable if NFS is not implemented. - Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes spec_store_bypass_disable=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spec_store_bypass_disable=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*spec_store_bypass_disable=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'spec_store_bypass_disable=' -The command should not return any output. - Is it the case that SSB is not configured appropriately? + Is it the case that the correct value is not returned? @@ -262621,40 +286418,456 @@ $ sysctl net.ipv4.conf.default.accept_redirects Is it the case that the correct value is not returned? - - To verify that auditing of privileged command use is configured, run the -following command: -$ sudo grep usernetctl /etc/audit/audit.rules /etc/audit/rules.d/* -It should return a relevant line in the audit rules. - Is it the case that the command does not return a line, or the line is commented out? + + The runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.accept_source_route +0. + + Is it the case that the correct value is not returned? - - Verify the operating system is not configured to bypass password requirements for privilege -escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: -$ sudo grep pam_succeed_if /etc/pam.d/sudo - Is it the case that system is configured to bypass password requirements for privilege escalation? + + The runtime status of the net.ipv4.conf.default.log_martians kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.log_martians +1. + + Is it the case that the correct value is not returned? - - To check the ownership of /etc/ssh/*.pub, -run the command: -$ ls -lL /etc/ssh/*.pub -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/*.pub does not have an owner of root? + + The runtime status of the net.ipv4.conf.default.rp_filter kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.rp_filter +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.secure_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.send_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.send_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.shared_media kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.shared_media +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.icmp_echo_ignore_broadcasts +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.icmp_ignore_bogus_error_responses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.ip_forward kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.ip_forward +0. +The ability to forward packets is only appropriate for routers. + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.ip_local_port_range kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.ip_local_port_range +32768 65535. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.tcp_rfc1337 kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.tcp_rfc1337 +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.tcp_syncookies kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.tcp_syncookies +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_defrtr +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_pinfo +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_rtr_pref +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.autoconf kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.autoconf +0. + + Is it the case that the correct value is not returned? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to prevent the usage of the ipv6 on +network interfaces, it will contain a line of the form: +net.ipv6.conf.all.disable_ipv6 = 1 +Such lines may be inside any file in the /etc/sysctl.d directory. +This permits insertion of the IPv6 kernel module (which other parts of the +system expect to be present), but otherwise keeps all network interfaces +from using IPv6. Run the following command to search for such lines in all +files in /etc/sysctl.d: +$ grep -r ipv6 /etc/sysctl.d + Is it the case that the ipv6 support is disabled on all network interfaces? + + + + The runtime status of the net.ipv6.conf.all.forwarding kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.forwarding +0. +The ability to forward packets is only appropriate for routers. + Is it the case that IP forwarding value is "1" and the system is not router? + + + + The runtime status of the net.ipv6.conf.all.max_addresses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.max_addresses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.router_solicitations +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_defrtr +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_pinfo +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_rtr_pref +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.autoconf kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.autoconf +0. + + Is it the case that the correct value is not returned? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to prevent the usage of the ipv6 on +network interfaces, it will contain a line of the form: +net.ipv6.conf.default.disable_ipv6 = 1 +Such lines may be inside any file in the /etc/sysctl.d directory. +This permits insertion of the IPv6 kernel module (which other parts of the +system expect to be present), but otherwise keeps network interfaces +from using IPv6. Run the following command to search for such lines in all +files in /etc/sysctl.d: +$ grep -r ipv6 /etc/sysctl.d + Is it the case that the ipv6 support is disabled by default on network interfaces? + + + + The runtime status of the net.ipv6.conf.default.max_addresses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.max_addresses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.router_solicitations +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 disables the use of user namespaces with the following commands: + +Note: User namespaces are used primarily for Linux containers. If containers are in use, this requirement is not applicable. + +The runtime status of the user.max_user_namespaces kernel parameter can be queried +by running the following command: +$ sysctl user.max_user_namespaces +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the vm.mmap_min_addr kernel parameter can be queried +by running the following command: +$ sysctl vm.mmap_min_addr +65536. + + Is it the case that the correct value is not returned? + + + + +Run the following command to determine the current status of the +tmp mount: +$ sudo systemctl is-active tmp.mount +If the mount unit is running, it should return the following: active + Is it the case that the tmp.mount unit is masked or disabled? + + + + Use sudo systemctl show tftp to verify that tftp service is using secure mode. +$ sudo systemctl show tftp | grep ExecStart= +ExecStart={ path=/usr/sbin/in.tftpd ; argv[]=/usr/sbin/in.tftpd -s /var/lib/tftpboot ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }e + + +and ensure the ExecStart line on that file includes the -s option with a subdirectory: +ExecStart=/usr/sbin/in.tftpd -s + Is it the case that the ExecStart property of tftp does not contain correctly set -s flag? + + + + Run the following command to determine the current status of the dnf-automatic timer: $ sudo systemctl is-active dnf-automatic.timer If the timer is running, it should return the following: active + Is it the case that the dnf-automatic.timer is not enabled? + + + + Run the following command to determine the current status of the logrotate timer: $ sudo systemctl is-active logrotate.timer If the timer is running, it should return the following: active + Is it the case that logrotate timer is not enabled? + + + + To verify that USB Human Interface Devices and hubs will be authorized by the USBGuard daemon, +run the following command: +$ sudo grep allow /etc/usbguard/rules.conf +The output lines should include +allow with-interface match-all { 03:*:* 09:00:* } + Is it the case that USB devices of class 3 and 9:00 are not authorized? + + + + Verify the USBGuard has a policy configured with the following command: + +$ usbguard list-rules + +allow id 1d6b:0001 serial + +If the command does not return results or an error is returned, ask the SA to indicate how unauthorized peripherals are being blocked. + Is it the case that there is no evidence that unauthorized peripherals are being blocked before establishing a connection? + + + + To verify the sec option is configured for all NFS mounts, run the following command: +$ grep "sec=" /etc/exports +All configured NFS exports should show the sec=krb5:krb5i:krb5p setting in parentheses. +This is not applicable if NFS is not implemented. + Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? + + + + Run the following command to check if the line is present: +grep pam_wheel /etc/pam.d/su +The output should contain the following line: +auth required pam_wheel.so use_uid + Is it the case that the line is not in the file or it is commented? + + + + Run the following command to check if the line is present: +grep pam_wheel /etc/pam.d/su +The output should contain the following line: +auth required pam_wheel.so use_uid group= + Is it the case that the line is not in the file or it is commented? + + + + Verify that there are no wireless interfaces configured on the system +with the following command: + +Note: This requirement is Not Applicable for systems that do not have physical wireless network radios. + +$ nmcli device status +DEVICE TYPE STATE CONNECTION +virbr0 bridge connected virbr0 +wlp7s0 wifi connected wifiSSID +enp6s0 ethernet disconnected -- +p2p-dev-wlp7s0 wifi-p2p disconnected -- +lo loopback unmanaged -- +virbr0-nic tun unmanaged -- + Is it the case that a wireless interface is configured and has not been documented and approved by the Information System Security Officer (ISSO)? + + + + To ensure the X Windows package group is removed, run the following command: +$ rpm -qi xorg-x11-server-Xorg +$ rpm -qi xorg-x11-server-common +$ rpm -qi xorg-x11-server-utils +$ rpm -qi xorg-x11-server-Xwayland +For each package mentioned above you should receive following line: +package <package> is not installed + Is it the case that xorg related packages are not removed and run level is not correctly configured? + + + + Verify that Oracle Linux 9 is configured to boot to the command line: +$ systemctl get-default +multi-user.target + Is it the case that the system default target is not set to "multi-user.target" and the Information System Security Officer (ISSO) lacks a documented requirement for a graphical user interface? - + build_cpe.py from SCAP Security Guide - ssg: [0, 1, 76], python: 3.9.21 + ssg: [0, 1, 79], python: 3.9.23 5.11 - 2025-05-06T00:00:00 + 2025-12-16T00:00:00 @@ -262669,6 +286882,10 @@ root + + + + @@ -262766,18 +286983,6 @@ root - - - Test that the architecture is ppc64le - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel is ppc64le - - - - - Test that the architecture is s390x @@ -262842,32 +287047,6 @@ root - - - Non-UEFI system boot mode check - - Oracle Linux 9 - - - Check if System boot mode is non-UEFI. - - - - - - - - UEFI system boot mode check - - Oracle Linux 9 - - - Check if system boot mode is UEFI. - - - - - @@ -262936,6 +287115,23 @@ root + + + Mountpoint /boot/efi is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + Mountpoint /home is active (mounted) or configured in /etc/fstab @@ -263271,6 +287467,18 @@ root + + + Package libpwquality is installed + + Oracle Linux 9 + + The RPM package libpwquality should be installed. + + + + + Package libreswan is installed @@ -263557,9 +287765,12 @@ root - - - + + + + + + @@ -263573,9 +287784,12 @@ root - - - + + + + + + @@ -263589,9 +287803,12 @@ root - - - + + + + + + @@ -263609,6 +287826,13 @@ root + + + + + + + @@ -263630,9 +287854,6 @@ root - - - @@ -263653,10 +287874,7 @@ root - - - - + @@ -263685,6 +287903,12 @@ root + + + + + + @@ -263816,6 +288040,9 @@ root + + + @@ -263893,6 +288120,10 @@ root + + + + @@ -263904,6 +288135,10 @@ root + + + + @@ -263915,6 +288150,10 @@ root + + + + @@ -263932,6 +288171,12 @@ root openshift-kubelet + + /run/ostree-booted + + + /ostree + grub2-common @@ -263953,22 +288198,17 @@ root 1 - /proc/sys/kernel/(osrelease|arch) + ^/proc/sys/kernel/(osrelease|arch) ^.*\.aarch64$|^aarch64$ 1 - - /proc/sys/kernel/(osrelease|arch) - ^.*\.ppc64le$|^ppc64le$ - 1 - - /proc/sys/kernel/(osrelease|arch) + ^/proc/sys/kernel/(osrelease|arch) ^.*\.s390x$|^s390x$ 1 - /proc/sys/kernel/(osrelease|arch) + ^/proc/sys/kernel/(osrelease|arch) ^.*\.x86_64$|^x86_64$ 1 @@ -263989,12 +288229,8 @@ root ^[\s]*\[domain\/[^]]*]([^\n\[\]]*\n+)+?[\s]*id_provider[ \t]*=[ \t]*((?i)ldap)[ \t]*$ 1 - - /sys/firmware/efi - - - kernel + kernel-core kernel-uek @@ -264013,6 +288249,14 @@ root ^\s*GRUB_CMDLINE_LINUX=".*ipv6\.disable=(\d).*$ 1 + + /boot/efi + + + /etc/fstab + ^[\s]*[\S]+[\s]+/boot/efi[\s]+[\S]+[\s]+([\S]+) + 1 + /home @@ -264174,6 +288418,9 @@ root iptables + + libpwquality + libreswan @@ -264278,6 +288525,10 @@ root + + /ostree + symbolic link + 1 @@ -264347,19 +288598,6817 @@ root masked + + not-found + inactive|failed masked + + not-found + inactive|failed masked + + not-found + + + #!/bin/bash +if [[ $(systemctl is-enabled dnf-automatic.timer) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled debug-shell.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled pcscd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rsyslog.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled systemd-journald.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled logrotate.timer) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled syslog-ng.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled firewalld.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled iptables.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash + +# Pass rule if IPv6 is disabled on kernel +if [ ! -e /proc/sys/net/ipv6/conf/all/disable_ipv6 ] || [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6)" -eq 1 ]; then + exit "$XCCDF_RESULT_PASS" +fi + +output="$(ip6tables -L | grep Chain)" +if [ -z "${output}" ]; then + exit "$XCCDF_RESULT_FAIL" +fi + +while read -r line; do + chain=$(echo "$line" | cut -f1-2 -d' ') + policy=$(echo "$line" | cut -f4 -d' ' | tr -d ')') + if [ "$chain" = "Chain INPUT" ] || [ "$chain" = "Chain FORWARD" ] || + [ "$chain" = "Chain OUTPUT" ]; then + if [ "$policy" != "DROP" ] && [ "$policy" != "REJECT" ]; then + exit "$XCCDF_RESULT_FAIL" + fi + fi +done <<< "$output" + +exit "$XCCDF_RESULT_PASS" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="1" +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="1" +check_sysctl_configuration "net.ipv6.conf.default.disable_ipv6" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_defrtr_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra_defrtr" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_pinfo_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra_pinfo" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra_rtr_pref" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_redirects_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_source_route_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_autoconf_value" +check_sysctl_configuration "net.ipv6.conf.all.autoconf" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_forwarding_value" +check_sysctl_configuration "net.ipv6.conf.all.forwarding" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_max_addresses_value" +check_sysctl_configuration "net.ipv6.conf.all.max_addresses" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_router_solicitations_value" +check_sysctl_configuration "net.ipv6.conf.all.router_solicitations" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_defrtr_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra_defrtr" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_pinfo_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra_pinfo" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra_rtr_pref" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_redirects_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_source_route_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_autoconf_value" +check_sysctl_configuration "net.ipv6.conf.default.autoconf" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_max_addresses_value" +check_sysctl_configuration "net.ipv6.conf.default.max_addresses" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_router_solicitations_value" +check_sysctl_configuration "net.ipv6.conf.default.router_solicitations" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.all.accept_local" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_accept_redirects_value" +check_sysctl_configuration "net.ipv4.conf.all.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_accept_source_route_value" +check_sysctl_configuration "net.ipv4.conf.all.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_arp_filter_value" +check_sysctl_configuration "net.ipv4.conf.all.arp_filter" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_arp_ignore_value" +check_sysctl_configuration "net.ipv4.conf.all.arp_ignore" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "net.ipv4.conf.all.drop_gratuitous_arp" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_forwarding_value" +check_sysctl_configuration "net.ipv4.conf.all.forwarding" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_log_martians_value" +check_sysctl_configuration "net.ipv4.conf.all.log_martians" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.all.route_localnet" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_rp_filter_value" +check_sysctl_configuration "net.ipv4.conf.all.rp_filter" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_secure_redirects_value" +check_sysctl_configuration "net.ipv4.conf.all.secure_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_shared_media_value" +check_sysctl_configuration "net.ipv4.conf.all.shared_media" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_accept_redirects_value" +check_sysctl_configuration "net.ipv4.conf.default.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_accept_source_route_value" +check_sysctl_configuration "net.ipv4.conf.default.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_log_martians_value" +check_sysctl_configuration "net.ipv4.conf.default.log_martians" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_rp_filter_value" +check_sysctl_configuration "net.ipv4.conf.default.rp_filter" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_secure_redirects_value" +check_sysctl_configuration "net.ipv4.conf.default.secure_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_shared_media_value" +check_sysctl_configuration "net.ipv4.conf.default.shared_media" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" +check_sysctl_configuration "net.ipv4.icmp_echo_ignore_broadcasts" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" +check_sysctl_configuration "net.ipv4.icmp_ignore_bogus_error_responses" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="32768 65535" +check_sysctl_configuration "net.ipv4.ip_local_port_range" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_tcp_rfc1337_value" +check_sysctl_configuration "net.ipv4.tcp_rfc1337" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_tcp_syncookies_value" +check_sysctl_configuration "net.ipv4.tcp_syncookies" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.all.send_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.default.send_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.ip_forward" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/bin/bash +if [[ $(systemctl is-enabled nftables.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled ufw.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "fs.protected_fifos" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "fs.protected_hardlinks" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "fs.protected_regular" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "fs.protected_symlinks" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/bin/bash +if [[ $(systemctl is-enabled autofs.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="|/bin/false" +check_sysctl_configuration "kernel.core_pattern" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "kernel.core_uses_pid" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.dmesg_restrict" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.kexec_load_disabled" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.modules_disabled" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.panic_on_oops" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.perf_cpu_time_max_percent" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.perf_event_max_sample_rate" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "kernel.perf_event_paranoid" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="65536" +check_sysctl_configuration "kernel.pid_max" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "kernel.sysrq" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.unprivileged_bpf_disabled" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + + +check_sysctl_configuration "kernel.unprivileged_bpf_disabled" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +check_sysctl_configuration "kernel.unprivileged_bpf_disabled" "2" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.yama.ptrace_scope" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "net.core.bpf_jit_harden" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "user.max_user_namespaces" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="65536" +check_sysctl_configuration "vm.mmap_min_addr" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/bin/bash +if [[ $(systemctl is-enabled systemd-coredump.socket) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "fs.suid_dumpable" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + + +check_sysctl_configuration "kernel.kptr_restrict" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +check_sysctl_configuration "kernel.kptr_restrict" "2" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "kernel.randomize_va_space" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_auditadm_exec_content" + +check_sebool_value auditadm_exec_content "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_authlogin_nsswitch_use_ldap" + +check_sebool_value authlogin_nsswitch_use_ldap "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_authlogin_radius" + +check_sebool_value authlogin_radius "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_deny_execmem" + +check_sebool_value deny_execmem "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_kerberos_enabled" + +check_sebool_value kerberos_enabled "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_polyinstantiation_enabled" + +check_sebool_value polyinstantiation_enabled "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_secure_mode_insmod" + +check_sebool_value secure_mode_insmod "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_selinuxuser_execheap" + +check_sebool_value selinuxuser_execheap "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_selinuxuser_execmod" + +check_sebool_value selinuxuser_execmod "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_selinuxuser_execstack" + +check_sebool_value selinuxuser_execstack "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_ssh_sysadm_login" + +check_sebool_value ssh_sysadm_login "$expected_value" +exit $? + + + + #!/bin/bash +if [[ $(systemctl is-enabled avahi-daemon.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled kdump.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled oddjobd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rdisc.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled crond.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled atd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled fapolicyd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled postfix.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled chronyd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rsyncd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rlogin.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled telnet.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled squid.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rngd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled snmpd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled sshd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled sshd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + +user_list=$(awk -F: -n '{ if ($7 !~ /\/s?bin\/false/ && $7 !~ /\/s?bin\/nologin/) { print $0; } }' /etc/passwd) +user_dirs=$(cut -d: -f6 <<<"${user_list}" | sort | uniq) +for dir in ${user_dirs} +do + pubkeys=$(find "${dir}/.ssh/" -type f -name '*.pub') + for pubkey in ${pubkeys} + do + ssh-keygen -y -P "" -f "${pubkey%.pub}" >/dev/null + if [ $? -ne 255 ]; then + echo "Key '${pubkey}' is not passphrase-protected" + exit "${XCCDF_RESULT_FAIL}" + fi + done +done + +exit "${XCCDF_RESULT_PASS}" + + + + #!/bin/bash +if [[ $(systemctl is-enabled sssd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled usbguard.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled auditd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + diff --git a/salt/strelka/backend/enabled.sls b/salt/strelka/backend/enabled.sls index 3a830c9b0..ca3f0e6dc 100644 --- a/salt/strelka/backend/enabled.sls +++ b/salt/strelka/backend/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -18,29 +18,35 @@ strelka_backend: - binds: - /opt/so/conf/strelka/backend/:/etc/strelka/:ro - /opt/so/conf/strelka/rules/compiled/:/etc/yara/:ro - {% if DOCKER.containers['so-strelka-backend'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-strelka-backend'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-strelka-backend'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-strelka-backend'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - name: so-strelka-backend - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-backend'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-strelka-backend'].ip }} - command: strelka-backend - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-strelka-backend'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-strelka-backend'].extra_hosts %} + {% if DOCKERMERGED.containers['so-strelka-backend'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-strelka-backend'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-strelka-backend'].extra_env %} + {% if DOCKERMERGED.containers['so-strelka-backend'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-strelka-backend'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-backend'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-strelka-backend'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-strelka-backend'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - restart_policy: on-failure - watch: - file: strelkasensorcompiledrules diff --git a/salt/strelka/coordinator/enabled.sls b/salt/strelka/coordinator/enabled.sls index 3440cd5a4..6756a324c 100644 --- a/salt/strelka/coordinator/enabled.sls +++ b/salt/strelka/coordinator/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -18,32 +18,38 @@ strelka_coordinator: - name: so-strelka-coordinator - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-coordinator'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-strelka-coordinator'].ip }} - entrypoint: redis-server --save "" --appendonly no - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-strelka-coordinator'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-strelka-coordinator'].extra_hosts %} + {% if DOCKERMERGED.containers['so-strelka-coordinator'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-strelka-coordinator'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-strelka-coordinator'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-strelka-coordinator'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-strelka-coordinator'].extra_env %} + {% if DOCKERMERGED.containers['so-strelka-coordinator'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-strelka-coordinator'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-coordinator'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} - binds: - /nsm/strelka/coord-redis-data:/data:rw - {% if DOCKER.containers['so-strelka-coordinator'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-strelka-coordinator'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-strelka-coordinator'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-strelka-coordinator'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-strelka-coordinator'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-strelka-coordinator'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} delete_so-strelka-coordinator_so-status.disabled: file.uncomment: - name: /opt/so/conf/so-status/so-status.conf diff --git a/salt/strelka/filestream/config.sls b/salt/strelka/filestream/config.sls index 2809bd8b1..2eaee7b53 100644 --- a/salt/strelka/filestream/config.sls +++ b/salt/strelka/filestream/config.sls @@ -47,12 +47,6 @@ filestream_config: FILESTREAMCONFIG: {{ STRELKAMERGED.filestream.config }} # Filecheck Section -{% if GLOBALS.os_family == 'Debian' %} -install_watchdog: - pkg.installed: - - name: python3-watchdog - -{% elif GLOBALS.os_family == 'RedHat' %} remove_old_watchdog: pkg.removed: - name: python3-watchdog @@ -60,7 +54,6 @@ remove_old_watchdog: install_watchdog: pkg.installed: - name: securityonion-python39-watchdog -{% endif %} filecheck_logdir: file.directory: diff --git a/salt/strelka/filestream/enabled.sls b/salt/strelka/filestream/enabled.sls index ef5d593ba..b03faf4b1 100644 --- a/salt/strelka/filestream/enabled.sls +++ b/salt/strelka/filestream/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -18,29 +18,35 @@ strelka_filestream: - binds: - /opt/so/conf/strelka/filestream/:/etc/strelka/:ro - /nsm/strelka:/nsm/strelka - {% if DOCKER.containers['so-strelka-filestream'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-strelka-filestream'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-strelka-filestream'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-strelka-filestream'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - name: so-strelka-filestream - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-filestream'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-strelka-filestream'].ip }} - command: strelka-filestream - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-strelka-filestream'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-strelka-filestream'].extra_hosts %} + {% if DOCKERMERGED.containers['so-strelka-filestream'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-strelka-filestream'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-strelka-filestream'].extra_env %} + {% if DOCKERMERGED.containers['so-strelka-filestream'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-strelka-filestream'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-filestream'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-strelka-filestream'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-strelka-filestream'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: filestream_config diff --git a/salt/strelka/frontend/enabled.sls b/salt/strelka/frontend/enabled.sls index 709b3e71c..58e703898 100644 --- a/salt/strelka/frontend/enabled.sls +++ b/salt/strelka/frontend/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -18,8 +18,8 @@ strelka_frontend: - binds: - /opt/so/conf/strelka/frontend/:/etc/strelka/:ro - /nsm/strelka/log/:/var/log/strelka/:rw - {% if DOCKER.containers['so-strelka-frontend'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-strelka-frontend'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-strelka-frontend'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-strelka-frontend'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} @@ -27,25 +27,31 @@ strelka_frontend: - name: so-strelka-frontend - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-frontend'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-strelka-frontend'].ip }} - command: strelka-frontend - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-strelka-frontend'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-strelka-frontend'].extra_hosts %} + {% if DOCKERMERGED.containers['so-strelka-frontend'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-strelka-frontend'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-strelka-frontend'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-strelka-frontend'].port_bindings %} - {{ BINDING }} {% endfor %} - {% if DOCKER.containers['so-strelka-frontend'].extra_env %} + {% if DOCKERMERGED.containers['so-strelka-frontend'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-strelka-frontend'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-frontend'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-strelka-frontend'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-strelka-frontend'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: frontend_config diff --git a/salt/strelka/gatekeeper/enabled.sls b/salt/strelka/gatekeeper/enabled.sls index 8d06ddf6a..45b6e467e 100644 --- a/salt/strelka/gatekeeper/enabled.sls +++ b/salt/strelka/gatekeeper/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -18,32 +18,38 @@ strelka_gatekeeper: - name: so-strelka-gatekeeper - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-gatekeeper'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-strelka-gatekeeper'].ip }} - entrypoint: redis-server --save "" --appendonly no --maxmemory-policy allkeys-lru - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-strelka-gatekeeper'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-strelka-gatekeeper'].extra_hosts %} + {% if DOCKERMERGED.containers['so-strelka-gatekeeper'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-strelka-gatekeeper'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - port_bindings: - {% for BINDING in DOCKER.containers['so-strelka-gatekeeper'].port_bindings %} + {% for BINDING in DOCKERMERGED.containers['so-strelka-gatekeeper'].port_bindings %} - {{ BINDING }} {% endfor %} - binds: - /nsm/strelka/gk-redis-data:/data:rw - {% if DOCKER.containers['so-strelka-gatekeeper'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-strelka-gatekeeper'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-strelka-gatekeeper'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-strelka-gatekeeper'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-strelka-gatekeeper'].extra_env %} + {% if DOCKERMERGED.containers['so-strelka-gatekeeper'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-strelka-gatekeeper'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-gatekeeper'].extra_env %} - {{ XTRAENV }} {% endfor %} - {% endif %} + {% endif %} + {% if DOCKERMERGED.containers['so-strelka-gatekeeper'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-strelka-gatekeeper'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} delete_so-strelka-gatekeeper_so-status.disabled: file.uncomment: diff --git a/salt/strelka/manager/enabled.sls b/salt/strelka/manager/enabled.sls index 6158a5c28..7c73452d8 100644 --- a/salt/strelka/manager/enabled.sls +++ b/salt/strelka/manager/enabled.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'vars/globals.map.jinja' import GLOBALS %} include: @@ -17,29 +17,35 @@ strelka_manager: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }} - binds: - /opt/so/conf/strelka/manager/:/etc/strelka/:ro - {% if DOCKER.containers['so-strelka-manager'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-strelka-manager'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-strelka-manager'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-strelka-manager'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - name: so-strelka-manager - networks: - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-manager'].ip }} + - ipv4_address: {{ DOCKERMERGED.containers['so-strelka-manager'].ip }} - command: strelka-manager - extra_hosts: - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - {% if DOCKER.containers['so-strelka-manager'].extra_hosts %} - {% for XTRAHOST in DOCKER.containers['so-strelka-manager'].extra_hosts %} + {% if DOCKERMERGED.containers['so-strelka-manager'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-strelka-manager'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-strelka-manager'].extra_env %} + {% if DOCKERMERGED.containers['so-strelka-manager'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-strelka-manager'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-strelka-manager'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-strelka-manager'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-strelka-manager'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: - file: manager_config diff --git a/salt/strelka/soc_strelka.yaml b/salt/strelka/soc_strelka.yaml index 1a5db261b..0066bd6c3 100644 --- a/salt/strelka/soc_strelka.yaml +++ b/salt/strelka/soc_strelka.yaml @@ -1,74 +1,75 @@ strelka: backend: - enabled: + enabled: description: Enables or disables the Strelka file analysis process. - helpLink: strelka.html + forcedType: bool + helpLink: strelka config: backend: logging_cfg: description: Path to the Python logging configuration. readonly: True global: False - helpLink: strelka.html + helpLink: strelka advanced: True limits: max_files: description: Number of files the backend will process before shutting down. readonly: False global: False - helpLink: strelka.html + helpLink: strelka time_to_live: description: Amount of time (in seconds) that the backend will run before shutting down (0 to disable). readonly: False global: False - helpLink: strelka.html + helpLink: strelka max_depth: description: Maximum depth that extracted files will be processed by the backend. readonly: False global: False - helpLink: strelka.html + helpLink: strelka distribution: description: Amount of time (in seconds) that a single file can be distributed to all scanners. readonly: False global: False - helpLink: strelka.html + helpLink: strelka scanner: description: Amount of time (in seconds) that a scanner can spend scanning a file (can be overridden per scanner). readonly: False global: False - helpLink: strelka.html + helpLink: strelka coordinator: addr: description: Network address of the coordinator. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True db: description: Redis database of the coordinator. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True tasting: mime_db: description: Location of the MIME database used to taste files. readonly: True global: False - helpLink: strelka.html + helpLink: strelka advanced: True yara_rules: description: Location of the directory of YARA files that contains rules used to taste files. readonly: True global: False - helpLink: strelka.html + helpLink: strelka advanced: True scanners: 'ScanBase64PE': &scannerOptions description: Configuration options for this scanner. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True forcedType: "[]{}" syntax: json @@ -139,7 +140,7 @@ strelka: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True formatters: simple: @@ -147,13 +148,13 @@ strelka: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True datefmt: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True handlers: console: @@ -161,32 +162,32 @@ strelka: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True formatter: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True stream: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True root: level: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True handlers: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True loggers: OpenSSL: @@ -194,425 +195,433 @@ strelka: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True bs4: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True bz2: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True chardet: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True docx: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True elftools: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True email: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True entropy: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True esprima: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True gzip: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True hashlib: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True json: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True libarchive: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True lxml: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True lzma: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True macholibre: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True olefile: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True oletools: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True pdfminer: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True pefile: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True pgpdump: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True pygments: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True pylzma: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True rarfile: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True requests: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True rpmfile: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True ssdeep: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True tarfile: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True tnefparse: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True yara: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True zipfile: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True zlib: propagate: description: This is an advanced option for Strelka logging. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True passwords: description: Passwords that will be stored in the password_file used in scanner options. readonly: False global: False - helpLink: strelka.html + helpLink: strelka multiline: True filestream: - enabled: + enabled: description: You can enable or disable Strelka filestream. - helpLink: strelka.html + forcedType: bool + helpLink: strelka config: conn: server: description: Network address of the frontend server. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True cert: description: Local path to the frontend SSL server certificate. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True timeout: dial: description: Amount of time to wait for the client to dial the server. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True file: description: Amount of time to wait for an individual file to complete a scan. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True throughput: concurrency: description: Number of concurrent requests to make. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True chunk: description: Size of file chunks that will be sent to the frontend server. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True delay: description: Artificial sleep between the submission of each chunk. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True files: patterns: description: List of glob patterns that determine which files will be sent for scanning. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True delete: description: Boolean that determines if files should be deleted after being sent for scanning. + forcedType: bool readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True gatekeeper: description: Boolean that determines if events should be pulled from the temporary event cache. + forcedType: bool readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True processed: description: Directory where files will be moved after being submitted for scanning. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True response: report: description: Frequency at which the frontend reports the number of files processed. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True delta: description: Time value that determines how much time must pass since a file was last modified before it is sent for scanning. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True staging: description: Directory where files are staged before being sent to the cluster. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True frontend: - enabled: + enabled: description: You can enable or disable Strelka frontend. - helpLink: strelka.html + forcedType: bool + helpLink: strelka config: server: description: Network address of the frontend server. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True coordinator: addr: description: Network address of the coordinator. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True db: description: Redis database of the coordinator. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True gatekeeper: addr: description: Network address of the gatekeeper. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True db: description: Redis database of the gatekeeper. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True ttl: description: Time-to-live for events added to the gatekeeper. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True response: log: description: Location where worker scan results are logged to. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True manager: - enabled: + enabled: description: You can enable or disable Strelka manager. - helpLink: strelka.html + forcedType: bool + helpLink: strelka config: coordinator: addr: description: Network address of the coordinator. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True db: description: Redis database of the coordinator. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True coordinator: - enabled: + enabled: description: You can enable or disable Strelka coordinator. - helpLink: strelka.html + forcedType: bool + helpLink: strelka gatekeeper: - enabled: + enabled: description: You can enable or disable Strelka gatekeeper. - helpLink: strelka.html + forcedType: bool + helpLink: strelka rules: enabled: description: Boolean that determines if yara rules sync from the Salt manager to the backend nodes. + forcedType: bool readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: False filecheck: historypath: description: The path for previously scanned files. readonly: True global: False - helpLink: strelka.html + helpLink: strelka advanced: True strelkapath: description: The path for unprocessed files. readonly: True global: False - helpLink: strelka.html + helpLink: strelka advanced: True logfile: description: The path for the filecheck log. readonly: False global: False - helpLink: strelka.html + helpLink: strelka advanced: True diff --git a/salt/suricata/config.sls b/salt/suricata/config.sls index e0b85b7e7..da75580e3 100644 --- a/salt/suricata/config.sls +++ b/salt/suricata/config.sls @@ -10,7 +10,7 @@ {% from 'suricata/map.jinja' import SURICATAMERGED %} {% from 'bpf/suricata.map.jinja' import SURICATABPF, SURICATA_BPF_STATUS, SURICATA_BPF_CALC %} -{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} +{% if GLOBALS.pcap_engine in ["SURICATA"] %} {% from 'bpf/pcap.map.jinja' import PCAPBPF, PCAP_BPF_STATUS, PCAP_BPF_CALC %} # BPF compilation and configuration {% if PCAPBPF and not PCAP_BPF_STATUS %} diff --git a/salt/suricata/defaults.yaml b/salt/suricata/defaults.yaml index cdb243465..818a7bf89 100644 --- a/salt/suricata/defaults.yaml +++ b/salt/suricata/defaults.yaml @@ -1,19 +1,20 @@ suricata: enabled: False pcap: + enabled: false filesize: 1000mb maxsize: 25 compression: "none" - lz4-checksum: "no" + lz4-checksum: false lz4-level: 8 filename: "%n/so-pcap.%t" mode: "multi" - use-stream-depth: "no" + use-stream-depth: false conditional: "all" dir: "/nsm/suripcap" config: threading: - set-cpu-affinity: "no" + set-cpu-affinity: false cpu-affinity: management-cpu-set: cpu: @@ -28,17 +29,17 @@ suricata: interface: bond0 cluster-id: 59 cluster-type: cluster_flow - defrag: "yes" - use-mmap: "yes" - mmap-locked: "no" + defrag: true + use-mmap: true + mmap-locked: false threads: 1 - tpacket-v3: "yes" + tpacket-v3: true ring-size: 5000 block-size: 69632 block-timeout: 10 - use-emergency-flush: "yes" + use-emergency-flush: true buffer-size: 32768 - disable-promisc: "no" + disable-promisc: false checksum-checks: kernel vars: address-groups: @@ -104,15 +105,15 @@ suricata: - 6081 default-log-dir: /var/log/suricata/ stats: - enabled: "yes" + enabled: true interval: 30 outputs: fast: - enabled: "no" + enabled: false filename: fast.log - append: "yes" + append: true eve-log: - enabled: "yes" + enabled: true filetype: regular filename: /nsm/eve-%Y-%m-%d-%H:%M.json rotate-interval: hour @@ -121,106 +122,104 @@ suricata: community-id-seed: 0 types: alert: - payload: "no" + payload: false payload-buffer-size: 4kb - payload-printable: "yes" - packet: "yes" + payload-printable: true + packet: true metadata: app-layer: false flow: false rule: metadata: true raw: true - tagged-packets: "no" + tagged-packets: false xff: - enabled: "no" + enabled: false mode: extra-data deployment: reverse header: X-Forwarded-For unified2-alert: - enabled: "no" + enabled: false tls-store: - enabled: "no" - pcap-log: - enabled: "no" + enabled: false alert-debug: - enabled: "no" + enabled: false alert-prelude: - enabled: "no" + enabled: false stats: - enabled: "yes" + enabled: true filename: stats.log - append: "yes" - totals: "yes" - threads: "no" - null-values: "yes" + append: true + totals: true + threads: false + null-values: true drop: - enabled: "no" + enabled: false file-store: version: 2 - enabled: "no" + enabled: false xff: - enabled: "no" + enabled: false mode: extra-data deployment: reverse header: X-Forwarded-For tcp-data: - enabled: "no" + enabled: false type: file filename: tcp-data.log http-body-data: - enabled: "no" + enabled: false type: file filename: http-data.log lua: - enabled: "no" + enabled: false scripts: logging: default-log-level: notice outputs: - console: - enabled: "yes" + enabled: true - file: - enabled: "yes" + enabled: true level: info filename: suricata.log - syslog: - enabled: "no" + enabled: false facility: local5 format: "[%i] <%d> -- " app-layer: protocols: krb5: - enabled: "yes" + enabled: true snmp: - enabled: "yes" + enabled: true ikev2: - enabled: "yes" + enabled: true tls: - enabled: "yes" + enabled: true detection-ports: dp: 443 ja3-fingerprints: auto ja4-fingerprints: auto encryption-handling: track-only dcerpc: - enabled: "yes" + enabled: true ftp: - enabled: "yes" + enabled: true rdp: - enabled: "yes" + enabled: true ssh: - enabled: "yes" + enabled: true smtp: - enabled: "yes" - raw-extraction: "no" + enabled: true + raw-extraction: false mime: - decode-mime: "yes" - decode-base64: "yes" - decode-quoted-printable: "yes" + decode-mime: true + decode-base64: true + decode-quoted-printable: true header-value-depth: 2000 - extract-urls: "yes" - body-md5: "no" + extract-urls: true + body-md5: false inspected-tracker: content-limit: 100000 content-inspect-min-size: 32768 @@ -228,27 +227,27 @@ suricata: imap: enabled: detection-only smb: - enabled: "yes" + enabled: true detection-ports: dp: 139, 445 nfs: - enabled: "yes" + enabled: true tftp: - enabled: "yes" + enabled: true dns: global-memcap: 16mb state-memcap: 512kb request-flood: 500 tcp: - enabled: "yes" + enabled: true detection-ports: dp: 53 udp: - enabled: "yes" + enabled: true detection-ports: dp: 53 http: - enabled: "yes" + enabled: true libhtp: default-config: personality: IDS @@ -261,43 +260,43 @@ suricata: response-body-decompress-layer-limit: 2 http-body-inline: auto swf-decompression: - enabled: "no" + enabled: false type: both compress-depth: 100 KiB decompress-depth: 100 KiB - randomize-inspection-sizes: "yes" + randomize-inspection-sizes: true randomize-inspection-range: 10 - double-decode-path: "no" - double-decode-query: "no" + double-decode-path: false + double-decode-query: false server-config: modbus: - enabled: "yes" + enabled: true detection-ports: dp: 502 stream-depth: 0 dnp3: - enabled: "yes" + enabled: true detection-ports: dp: 20000 enip: - enabled: "yes" + enabled: true detection-ports: dp: 44818 sp: 44818 ntp: - enabled: "yes" + enabled: true dhcp: - enabled: "yes" + enabled: true sip: - enabled: "yes" + enabled: true rfb: - enabled: 'yes' + enabled: true detection-ports: dp: 5900, 5901, 5902, 5903, 5904, 5905, 5906, 5907, 5908, 5909 mqtt: - enabled: 'no' + enabled: false http2: - enabled: 'yes' + enabled: true asn1-max-frames: 256 run-as: user: suricata @@ -313,8 +312,8 @@ suricata: legacy: uricontent: enabled engine-analysis: - rules-fast-pattern: "yes" - rules: "yes" + rules-fast-pattern: true + rules: true pcre: match-limit: 3500 match-limit-recursion: 1500 @@ -337,7 +336,7 @@ suricata: hash-size: 65536 trackers: 65535 max-frags: 65535 - prealloc: "yes" + prealloc: true timeout: 60 flow: memcap: 128mb @@ -381,14 +380,14 @@ suricata: emergency-bypassed: 50 stream: memcap: 64mb - checksum-validation: "yes" + checksum-validation: true inline: auto reassembly: memcap: 256mb depth: 1mb toserver-chunk-size: 2560 toclient-chunk-size: 2560 - randomize-chunk-size: "yes" + randomize-chunk-size: true host: hash-size: 4096 prealloc: 1000 @@ -433,38 +432,38 @@ suricata: allow-restricted-functions: false profiling: rules: - enabled: "yes" + enabled: true filename: rule_perf.log - append: "yes" + append: true limit: 10 - json: "yes" + json: true keywords: - enabled: "yes" + enabled: true filename: keyword_perf.log - append: "yes" + append: true prefilter: - enabled: "yes" + enabled: true filename: prefilter_perf.log - append: "yes" + append: true rulegroups: - enabled: "yes" + enabled: true filename: rule_group_perf.log - append: "yes" + append: true packets: - enabled: "yes" + enabled: true filename: packet_stats.log - append: "yes" + append: true csv: - enabled: "no" + enabled: false filename: packet_stats.csv locks: - enabled: "no" + enabled: false filename: lock_stats.log - append: "yes" + append: true pcap-log: - enabled: "no" + enabled: false filename: pcaplog_stats.log - append: "yes" + append: true default-rule-path: /etc/suricata/rules rule-files: - all-rulesets.rules diff --git a/salt/suricata/enabled.sls b/salt/suricata/enabled.sls index ec521abb3..d9d7f32ae 100644 --- a/salt/suricata/enabled.sls +++ b/salt/suricata/enabled.sls @@ -6,7 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'suricata/map.jinja' import SURICATAMERGED %} @@ -20,16 +20,15 @@ so-suricata: - privileged: True - environment: - INTERFACE={{ GLOBALS.sensor.interface }} - {% if DOCKER.containers['so-suricata'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-suricata'].extra_env %} + {% if DOCKERMERGED.containers['so-suricata'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-suricata'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} - {# we look at SURICATAMERGED.config['af-packet'][0] since we only allow one interface and therefore always the first list item #} - {% if SURICATAMERGED.config['af-packet'][0]['mmap-locked'] == "yes" and DOCKER.containers['so-suricata'].ulimits %} + {% if DOCKERMERGED.containers['so-suricata'].ulimits %} - ulimits: - {% for ULIMIT in DOCKER.containers['so-suricata'].ulimits %} - - {{ ULIMIT }} + {% for ULIMIT in DOCKERMERGED.containers['so-suricata'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} {% endfor %} {% endif %} - binds: @@ -42,15 +41,15 @@ so-suricata: - /nsm/suricata/extracted:/var/log/suricata//filestore:rw - /opt/so/conf/suricata/bpf:/etc/suricata/bpf:ro - /nsm/suripcap/:/nsm/suripcap:rw - {% if DOCKER.containers['so-suricata'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-suricata'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-suricata'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-suricata'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - network_mode: host - {% if DOCKER.containers['so-suricata'].extra_hosts %} + {% if DOCKERMERGED.containers['so-suricata'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-suricata'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-suricata'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} diff --git a/salt/suricata/map.jinja b/salt/suricata/map.jinja index 3d378b69d..944e0e34d 100644 --- a/salt/suricata/map.jinja +++ b/salt/suricata/map.jinja @@ -9,15 +9,20 @@ {% set surimeta_filestore_index = [] %} {# before we change outputs back to list, enable pcap-log if suricata is the pcapengine #} -{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} +{% if GLOBALS.pcap_engine in ["SURICATA"] %} + +{# initialize pcap-log in config.outputs since we dont put it in defaults #} +{% if 'pcap-log' not in SURICATAMERGED.config.outputs %} +{% do SURICATAMERGED.config.outputs.update({'pcap-log': {}}) %} +{% endif %} {% from 'bpf/pcap.map.jinja' import PCAPBPF, PCAP_BPF_STATUS %} {% if PCAPBPF and PCAP_BPF_STATUS %} {% do SURICATAMERGED.config.outputs['pcap-log'].update({'bpf-filter': PCAPBPF|join(" ")}) %} {% endif %} -{% do SURICATAMERGED.config.outputs['pcap-log'].update({'enabled': 'yes'}) %} {# move the items in suricata.pcap into suricata.config.outputs.pcap-log. these items were placed under suricata.config for ease of access in SOC #} +{% do SURICATAMERGED.config.outputs['pcap-log'].update({'enabled': SURICATAMERGED.pcap.enabled}) %} {% do SURICATAMERGED.config.outputs['pcap-log'].update({'compression': SURICATAMERGED.pcap.compression}) %} {% do SURICATAMERGED.config.outputs['pcap-log'].update({'lz4-checksum': SURICATAMERGED.pcap['lz4-checksum']}) %} {% do SURICATAMERGED.config.outputs['pcap-log'].update({'lz4-level': SURICATAMERGED.pcap['lz4-level']}) %} @@ -38,22 +43,18 @@ - interface: {{ GLOBALS.sensor.interface }} cluster-id: {{ SURICATAMERGED.config['af-packet']['cluster-id'] }} cluster-type: {{ SURICATAMERGED.config['af-packet']['cluster-type'] }} - defrag: "{{ SURICATAMERGED.config['af-packet'].defrag }}" - use-mmap: "{{ SURICATAMERGED.config['af-packet']['use-mmap'] }}" - mmap-locked: "{{ SURICATAMERGED.config['af-packet']['mmap-locked'] }}" + defrag: {{ SURICATAMERGED.config['af-packet'].defrag }} + use-mmap: {{ SURICATAMERGED.config['af-packet']['use-mmap'] }} + mmap-locked: {{ SURICATAMERGED.config['af-packet']['mmap-locked'] }} threads: {{ SURICATAMERGED.config['af-packet'].threads }} - tpacket-v3: "{{ SURICATAMERGED.config['af-packet']['tpacket-v3'] }}" + tpacket-v3: {{ SURICATAMERGED.config['af-packet']['tpacket-v3'] }} ring-size: {{ SURICATAMERGED.config['af-packet']['ring-size'] }} block-size: {{ SURICATAMERGED.config['af-packet']['block-size'] }} block-timeout: {{ SURICATAMERGED.config['af-packet']['block-timeout'] }} - use-emergency-flush: "{{ SURICATAMERGED.config['af-packet']['use-emergency-flush'] }}" + use-emergency-flush: {{ SURICATAMERGED.config['af-packet']['use-emergency-flush'] }} buffer-size: {{ SURICATAMERGED.config['af-packet']['buffer-size'] }} - disable-promisc: "{{ SURICATAMERGED.config['af-packet']['disable-promisc'] }}" -{% if SURICATAMERGED.config['af-packet']['checksum-checks'] in ['yes', 'no'] %} - checksum-checks: "{{ SURICATAMERGED.config['af-packet']['checksum-checks'] }}" -{% else %} + disable-promisc: {{ SURICATAMERGED.config['af-packet']['disable-promisc'] }} checksum-checks: {{ SURICATAMERGED.config['af-packet']['checksum-checks'] }} -{% endif %} {% endload %} {% do SURICATAMERGED.config.pop('af-packet') %} {% do SURICATAMERGED.config.update({'af-packet': afpacket}) %} diff --git a/salt/suricata/pcap.sls b/salt/suricata/pcap.sls index 87b568f96..c557b6cda 100644 --- a/salt/suricata/pcap.sls +++ b/salt/suricata/pcap.sls @@ -2,7 +2,7 @@ {% from 'suricata/map.jinja' import SURICATAMERGED %} # This directory needs to exist regardless of whether SURIPCAP is enabled or not, in order for -# Sensoroni to be able to look at old Suricata PCAP data +# Sensoroni to mount it suripcapdir: file.directory: - name: /nsm/suripcap @@ -11,7 +11,14 @@ suripcapdir: - mode: 775 - makedirs: True -{% if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} +pcapoutdir: + file.directory: + - name: /nsm/pcapout + - user: 939 + - group: 939 + - makedirs: True + +{% if GLOBALS.pcap_engine in ["SURICATA"] %} {# there should only be 1 interface in af-packet so we can just reference the first list item #} {% for i in range(1, SURICATAMERGED.config['af-packet'][0].threads + 1) %} diff --git a/salt/suricata/rules/.gitkeep b/salt/suricata/rules/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/salt/suricata/soc_suricata.yaml b/salt/suricata/soc_suricata.yaml index 03f30be75..c85b876a9 100644 --- a/salt/suricata/soc_suricata.yaml +++ b/salt/suricata/soc_suricata.yaml @@ -1,7 +1,8 @@ suricata: - enabled: + enabled: description: Enables or disables the Suricata process. This process is used for triggering alerts and optionally for protocol metadata collection and full packet capture. - helpLink: suricata.html + forcedType: bool + helpLink: suricata thresholding: sids__yaml: description: Threshold SIDS List. This setting is readonly; Use the Detections screen to modify rules. @@ -10,7 +11,7 @@ suricata: global: True multiline: True title: SIDS - helpLink: suricata.html + helpLink: suricata readonlyUi: True advanced: True classification: @@ -20,79 +21,84 @@ suricata: global: True multiline: True title: Classifications - helpLink: suricata.html + helpLink: suricata pcap: + enabled: + description: Enables or disables the Suricata packet recording process. + forcedType: bool + helpLink: suricata filesize: description: Maximum file size for individual PCAP files written by Suricata. Increasing this number could improve write performance at the expense of pcap retrieval time. advanced: True - helpLink: suricata.html + helpLink: suricata maxsize: description: Maximum size in GB for total disk usage of all PCAP files written by Suricata. - helpLink: suricata.html + helpLink: suricata compression: description: Enable compression of Suricata PCAP files. advanced: True - helpLink: suricata.html - lz4-checksum: + helpLink: suricata + lz4-checksum: description: Enable PCAP lz4 checksum. + forcedType: bool advanced: True - helpLink: suricata.html + helpLink: suricata lz4-level: description: lz4 compression level of PCAP files. Set to 0 for no compression. Set to 16 for maximum compression. advanced: True - helpLink: suricata.html + helpLink: suricata filename: description: Filename output for Suricata PCAP files. advanced: True readonly: True - helpLink: suricata.html + helpLink: suricata mode: description: Suricata PCAP mode. Currently only multi is supported. advanced: True readonly: True - helpLink: suricata.html - use-stream-depth: - description: Set to "no" to ignore the stream depth and capture the entire flow. Set to "yes" to truncate the flow based on the stream depth. + helpLink: suricata + use-stream-depth: + description: Set to false to ignore the stream depth and capture the entire flow. Set to true to truncate the flow based on the stream depth. + forcedType: bool advanced: True - regex: ^(yes|no)$ - regexFailureMessage: You must enter either yes or no. - helpLink: suricata.html + helpLink: suricata conditional: description: Set to "all" to record PCAP for all flows. Set to "alerts" to only record PCAP for Suricata alerts. Set to "tag" to only record PCAP for tagged rules. regex: ^(all|alerts|tag)$ regexFailureMessage: You must enter either all, alert or tag. - helpLink: suricata.html + helpLink: suricata dir: description: Parent directory to store PCAP. advanced: True readonly: True - helpLink: suricata.html + helpLink: suricata config: af-packet: interface: description: The network interface that Suricata will monitor. This is set under sensor > interface. advanced: True readonly: True - helpLink: suricata.html + helpLink: suricata cluster-id: advanced: True cluster-type: advanced: True regex: ^(cluster_flow|cluster_qm)$ defrag: + description: Enable defragmentation of IP packets before processing. + forcedType: bool advanced: True - regex: ^(yes|no)$ use-mmap: advanced: True readonly: True mmap-locked: description: Prevent swapping by locking the memory map. + forcedType: bool advanced: True - regex: ^(yes|no)$ - helpLink: suricata.html + helpLink: suricata threads: description: The amount of worker threads. - helpLink: suricata.html + helpLink: suricata forcedType: int tpacket-v3: advanced: True @@ -100,68 +106,71 @@ suricata: ring-size: description: Buffer size for packets per thread. forcedType: int - helpLink: suricata.html + helpLink: suricata block-size: description: This must be configured to a sufficiently high value to accommodate a significant number of packets, considering byte size and MTU constraints. Ensure it aligns with a power of 2 and is a multiple of the page size. advanced: True forcedType: int - helpLink: suricata.html + helpLink: suricata block-timeout: description: If a block remains unfilled after the specified block-timeout milliseconds, it is passed to userspace. advanced: True forcedType: int - helpLink: suricata.html + helpLink: suricata use-emergency-flush: - description: In high-traffic environments, enabling this option to 'yes' aids in recovering from packet drop occurrences. However, it may lead to some packets, possibly at max ring flush, not being inspected. + description: In high-traffic environments, enabling this option aids in recovering from packet drop occurrences. However, it may lead to some packets, possibly at max ring flush, not being inspected. + forcedType: bool advanced: True - regex: ^(yes|no)$ - helpLink: suricata.html + helpLink: suricata buffer-size: description: Increasing the value of the receive buffer may improve performance. advanced: True forcedType: int - helpLink: suricata.html + helpLink: suricata disable-promisc: - description: Promiscuous mode can be disabled by setting this to "yes". + description: Disable promiscuous mode on the capture interface. + forcedType: bool advanced: True - regex: ^(yes|no)$ - helpLink: suricata.html + helpLink: suricata checksum-checks: description: "Opt for the checksum verification mode suitable for the interface. During capture, it's possible that some packets may exhibit invalid checksums due to the network card handling the checksum computation. You have several options: 'kernel': Relies on indications sent by the kernel for each packet (default). 'yes': Enforces checksum validation. 'no': Disables checksum validation. 'auto': Suricata employs a statistical approach to detect checksum offloading." advanced: True - regex: ^(kernel|yes|no|auto)$ - helpLink: suricata.html + options: + - kernel + - yes + - no + - auto + helpLink: suricata threading: set-cpu-affinity: - description: Bind(yes) or unbind(no) management and worker threads to a core or range of cores. - regex: ^(yes|no)$ - regexFailureMessage: You must enter either yes or no. - helpLink: suricata.html + description: Bind or unbind management and worker threads to a core or range of cores. + forcedType: bool + helpLink: suricata cpu-affinity: management-cpu-set: cpu: - description: Bind management threads to a core or range of cores. This can be a sigle core, list of cores, or list of range of cores. set-cpu-affinity must be set to 'yes' for this to be used. + description: Bind management threads to a core or range of cores. This can be a sigle core, list of cores, or list of range of cores. set-cpu-affinity must be set to true for this to be used. forcedType: "[]string" - helpLink: suricata.html + helpLink: suricata worker-cpu-set: cpu: - description: Bind worker threads to a core or range of cores. This can be a sigle core, list of cores, or list of range of cores. set-cpu-affinity must be set to 'yes' for this to be used. + description: Bind worker threads to a core or range of cores. This can be a sigle core, list of cores, or list of range of cores. set-cpu-affinity must be set to true for this to be used. forcedType: "[]string" - helpLink: suricata.html + helpLink: suricata vars: address-groups: HOME_NET: description: Assign a list of hosts, or networks, using CIDR notation, to this Suricata variable. The variable can then be re-used within Suricata rules. This allows for a single adjustment to the variable that will then affect all rules referencing the variable. - regex: ^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/([0-9]|[1-2][0-9]|3[0-2]))?$|^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?))|:))|(([0-9A-Fa-f]{1,4}:){5}((:[0-9A-Fa-f]{1,4}){1,2}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){4}((:[0-9A-Fa-f]{1,4}){1,3}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){3}((:[0-9A-Fa-f]{1,4}){1,4}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){2}((:[0-9A-Fa-f]{1,4}){1,5}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){1}((:[0-9A-Fa-f]{1,4}){1,6}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(:((:[0-9A-Fa-f]{1,4}){1,7}|:)))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$ + regex: ^!?((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/([0-9]|[1-2][0-9]|3[0-2]))?$|^!?((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){5}((:[0-9A-Fa-f]{1,4}){1,2}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){4}((:[0-9A-Fa-f]{1,4}){1,3}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){3}((:[0-9A-Fa-f]{1,4}){1,4}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){2}((:[0-9A-Fa-f]{1,4}){1,5}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){1}((:[0-9A-Fa-f]{1,4}){1,6}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(:((:[0-9A-Fa-f]{1,4}){1,7}|:)))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$ regexFailureMessage: You must enter a valid IP address or CIDR. forcedType: "[]string" duplicates: True - helpLink: suricata.html + helpLink: suricata EXTERNAL_NET: &suriaddressgroup description: Assign a list of hosts, or networks, or other customization, to this Suricata variable. The variable can then be re-used within Suricata rules. This allows for a single adjustment to the variable that will then affect all rules referencing the variable. forcedType: "[]string" duplicates: True - helpLink: suricata.html + helpLink: suricata HTTP_SERVERS: *suriaddressgroup SMTP_SERVERS: *suriaddressgroup SQL_SERVERS: *suriaddressgroup @@ -180,7 +189,7 @@ suricata: description: Assign a list of network port numbers to this Suricata variable. The variable can then be re-used within Suricata rules. This allows for a single adjustment to the variable that will then affect all rules referencing the variable. forcedType: "[]string" duplicates: True - helpLink: suricata.html + helpLink: suricata SHELLCODE_PORTS: *suriportgroup ORACLE_PORTS: *suriportgroup SSH_PORTS: *suriportgroup @@ -194,115 +203,189 @@ suricata: GENEVE_PORTS: *suriportgroup outputs: eve-log: + pcap-file: + description: Log the PCAP filename that a packet was read from when processing pcap files. + forcedType: bool + advanced: True + helpLink: suricata + community-id: + description: Enable Community ID flow hashing for consistent event correlation across tools. + forcedType: bool + advanced: True + helpLink: suricata types: alert: + metadata: + app-layer: + description: Include app-layer metadata in alert events. + forcedType: bool + advanced: True + helpLink: suricata + flow: + description: Include flow metadata in alert events. + forcedType: bool + advanced: True + helpLink: suricata + rule: + metadata: + description: Include rule metadata in alert events. + forcedType: bool + advanced: True + helpLink: suricata + raw: + description: Include raw rule text in alert events. + forcedType: bool + advanced: True + helpLink: suricata xff: enabled: description: Enable X-Forward-For support. - helpLink: suricata.html + forcedType: bool + helpLink: suricata mode: description: Operation mode. This should always be extra-data if you use PCAP. - helpLink: suricata.html + helpLink: suricata deployment: description: forward would use the first IP address and reverse would use the last. - helpLink: suricata.html + helpLink: suricata header: description: Header name where the actual IP address will be reported. - helpLink: suricata.html - pcap-log: - enabled: - description: This value is ignored by SO. pcapengine in globals takes precedence. - readonly: True - helpLink: suricata.html - advanced: True + helpLink: suricata asn1-max-frames: description: Maximum nuber of asn1 frames to decode. - helpLink: suricata.html + helpLink: suricata max-pending-packets: description: Number of packets preallocated per thread. - helpLink: suricata.html + helpLink: suricata default-packet-size: description: Preallocated size for each packet. - helpLink: suricata.html + helpLink: suricata pcre: match-limit: description: Match limit for PCRE. - helpLink: suricata.html + helpLink: suricata match-limit-recursion: description: Recursion limit for PCRE. - helpLink: suricata.html + helpLink: suricata defrag: memcap: description: Max memory to use for defrag. You should only change this if you know what you are doing. - helpLink: suricata.html + helpLink: suricata hash-size: description: Hash size - helpLink: suricata.html + helpLink: suricata trackers: description: Number of defragmented flows to follow. - helpLink: suricata.html + helpLink: suricata max-frags: description: Max number of fragments to keep - helpLink: suricata.html - prealloc: + helpLink: suricata + prealloc: description: Preallocate memory. - helpLink: suricata.html + forcedType: bool + helpLink: suricata timeout: description: Timeout value. - helpLink: suricata.html + helpLink: suricata flow: memcap: description: Reserverd memory for flows. - helpLink: suricata.html + helpLink: suricata hash-size: description: Determines the size of the hash used to identify flows inside the engine. - helpLink: suricata.html + helpLink: suricata prealloc: description: Number of preallocated flows. - helpLink: suricata.html + helpLink: suricata stream: memcap: description: Can be specified in kb,mb,gb. - helpLink: suricata.html + helpLink: suricata checksum-validation: description: Validate checksum of packets. - helpLink: suricata.html + forcedType: bool + helpLink: suricata reassembly: memcap: description: Can be specified in kb,mb,gb. - helpLink: suricata.html + helpLink: suricata depth: description: Controls how far into a stream that reassembly is done. - helpLink: suricata.html + helpLink: suricata host: hash-size: description: Hash size in bytes. - helpLink: suricata.html + helpLink: suricata prealloc: description: How many streams to preallocate. - helpLink: suricata.html + helpLink: suricata memcap: description: Memory settings for host. - helpLink: suricata.html + helpLink: suricata decoder: teredo: enabled: description: Enable TEREDO capabilities - helpLink: suricata.html + forcedType: bool + helpLink: suricata ports: description: Ports to listen for. This should be a variable. - helpLink: suricata.html + helpLink: suricata vxlan: enabled: description: Enable VXLAN capabilities. - helpLink: suricata.html - ports: - description: Ports to listen for. This should be a variable. - helpLink: suricata.html + forcedType: bool + helpLink: suricata + ports: + description: Ports to listen for. This should be a variable. + helpLink: suricata geneve: enabled: description: Enable VXLAN capabilities. - helpLink: suricata.html - ports: - description: Ports to listen for. This should be a variable. - helpLink: suricata.html + forcedType: bool + helpLink: suricata + ports: + description: Ports to listen for. This should be a variable. + helpLink: suricata + recursion-level: + use-for-tracking: + description: Controls whether the decoder recursion level is used for flow tracking. + forcedType: bool + advanced: True + helpLink: suricata + vlan: + use-for-tracking: + description: Enable VLAN tracking for flow identification. When enabled, VLAN tags are used to differentiate flows. + forcedType: bool + advanced: True + helpLink: suricata + detect: + profiling: + grouping: + dump-to-disk: + description: Dump detection engine grouping information to disk for analysis. + forcedType: bool + advanced: True + helpLink: suricata + include-rules: + description: Include individual rule details in grouping profiling output. + forcedType: bool + advanced: True + helpLink: suricata + include-mpm-stats: + description: Include multi-pattern matcher statistics in grouping profiling output. + forcedType: bool + advanced: True + helpLink: suricata + security: + lua: + allow-rules: + description: Allow Lua rules in the Suricata ruleset. Enabling Lua rules may introduce security risks. + forcedType: bool + advanced: True + helpLink: suricata + allow-restricted-functions: + description: Allow restricted Lua functions such as file I/O. Enabling this may introduce security risks. + forcedType: bool + advanced: True + helpLink: suricata diff --git a/salt/suricata/tools/sbin_jinja/so-suricata-testrule b/salt/suricata/tools/sbin_jinja/so-suricata-testrule index d65b630b0..477dc7582 100755 --- a/salt/suricata/tools/sbin_jinja/so-suricata-testrule +++ b/salt/suricata/tools/sbin_jinja/so-suricata-testrule @@ -27,12 +27,13 @@ echo "" sleep 3 rm -rf /tmp/nids-testing/output -mkdir -p /tmp/nids-testing/output +mkdir -p /tmp/nids-testing/output/suripcap chown suricata:socore /tmp/nids-testing/output mkdir -p /tmp/nids-testing/rules -cp /opt/so/conf/suricata/rules/all.rules /tmp/nids-testing/rules/all.rules -cat $TESTRULE >> /tmp/nids-testing/rules/all.rules +cp /opt/so/rules/suricata/all-rulesets.rules /tmp/nids-testing/rules/all-rulesets.rules +cat $TESTRULE >> /tmp/nids-testing/rules/all-rulesets.rules + echo "==== Begin Suricata Output ===" @@ -44,7 +45,7 @@ echo "==== Begin Suricata Output ===" -v /opt/so/conf/suricata/bpf:/etc/suricata/bpf:ro \ -v /tmp/nids-testing/output/:/nsm/:rw \ {{ MANAGER }}:5000/{{ IMAGEREPO }}/so-suricata:{{ VERSION }} \ - --runmode single -v -k none -r /input.pcap -l /tmp --init-errors-fatal --set outputs.6.pcap-log.enabled=no + --runmode single -v -k none -r /input.pcap -l /tmp --init-errors-fatal echo "==== End Suricata Output ===" echo "" diff --git a/salt/telegraf/config.sls b/salt/telegraf/config.sls index 171bd41f5..3873d1da0 100644 --- a/salt/telegraf/config.sls +++ b/salt/telegraf/config.sls @@ -7,9 +7,7 @@ {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'telegraf/map.jinja' import TELEGRAFMERGED %} - -include: - - ssl +{% from 'logstash/map.jinja' import LOGSTASH_MERGED %} # add Telegraf to monitor all the things tgraflogdir: @@ -92,6 +90,7 @@ tgrafconf: - defaults: GLOBALS: {{ GLOBALS }} TELEGRAFMERGED: {{ TELEGRAFMERGED }} + LOGSTASH_MERGED: {{ LOGSTASH_MERGED }} # this file will be read by telegraf to send node details (management interface, monitor interface, etc) # into influx diff --git a/salt/telegraf/defaults.yaml b/salt/telegraf/defaults.yaml index c0a67b0ca..ef6c2bc77 100644 --- a/salt/telegraf/defaults.yaml +++ b/salt/telegraf/defaults.yaml @@ -7,8 +7,8 @@ telegraf: collection_jitter: '0s' flush_interval: '10s' flush_jitter: '0s' - debug: 'false' - quiet: 'false' + debug: false + quiet: false scripts: eval: - agentstatus.sh @@ -19,7 +19,6 @@ telegraf: - os.sh - raid.sh - sostatus.sh - - stenoloss.sh - suriloss.sh - surirules.sh - zeekcaptureloss.sh @@ -35,7 +34,6 @@ telegraf: - raid.sh - redis.sh - sostatus.sh - - stenoloss.sh - suriloss.sh - surirules.sh - zeekcaptureloss.sh @@ -81,7 +79,6 @@ telegraf: - os.sh - raid.sh - sostatus.sh - - stenoloss.sh - suriloss.sh - surirules.sh - zeekcaptureloss.sh @@ -96,7 +93,6 @@ telegraf: - raid.sh - redis.sh - sostatus.sh - - stenoloss.sh - suriloss.sh - surirules.sh - zeekcaptureloss.sh diff --git a/salt/telegraf/enabled.sls b/salt/telegraf/enabled.sls index 451c78dda..fc9946149 100644 --- a/salt/telegraf/enabled.sls +++ b/salt/telegraf/enabled.sls @@ -6,11 +6,12 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'telegraf/map.jinja' import TELEGRAFMERGED %} - include: + - ca + - telegraf.ssl - telegraf.config - telegraf.sostatus @@ -24,8 +25,8 @@ so-telegraf: - HOST_SYS=/host/sys - HOST_MOUNT_PREFIX=/host - GODEBUG=x509ignoreCN=0 - {% if DOCKER.containers['so-telegraf'].extra_env %} - {% for XTRAENV in DOCKER.containers['so-telegraf'].extra_env %} + {% if DOCKERMERGED.containers['so-telegraf'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-telegraf'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} @@ -42,15 +43,10 @@ so-telegraf: - /proc:/host/proc:ro - /nsm:/host/nsm:ro - /etc:/host/etc:ro - {% if GLOBALS.role in ['so-manager', 'so-eval', 'so-managersearch' ] %} - - /etc/pki/ca.crt:/etc/telegraf/ca.crt:ro - {% else %} - /etc/pki/tls/certs/intca.crt:/etc/telegraf/ca.crt:ro - {% endif %} - - /etc/pki/influxdb.crt:/etc/telegraf/telegraf.crt:ro - - /etc/pki/influxdb.key:/etc/telegraf/telegraf.key:ro + - /etc/pki/telegraf.crt:/etc/telegraf/telegraf.crt:ro + - /etc/pki/telegraf.key:/etc/telegraf/telegraf.key:ro - /opt/so/conf/telegraf/scripts:/scripts:ro - - /opt/so/log/stenographer:/var/log/stenographer:ro - /opt/so/log/suricata:/var/log/suricata:ro - /opt/so/log/raid:/var/log/raid:ro - /opt/so/log/sostatus:/var/log/sostatus:ro @@ -59,33 +55,38 @@ so-telegraf: {% if GLOBALS.is_manager or GLOBALS.role == 'so-heavynode' %} - /opt/so/conf/telegraf/etc/escurl.config:/etc/telegraf/elasticsearch.config:ro {% endif %} - {% if DOCKER.containers['so-telegraf'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-telegraf'].custom_bind_mounts %} + {% if DOCKERMERGED.containers['so-telegraf'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-telegraf'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-telegraf'].extra_hosts %} + {% if DOCKERMERGED.containers['so-telegraf'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-telegraf'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-telegraf'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} + {% if DOCKERMERGED.containers['so-telegraf'].ulimits %} + - ulimits: + {% for ULIMIT in DOCKERMERGED.containers['so-telegraf'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - watch: + - file: trusttheca + - x509: telegraf_crt + - x509: telegraf_key - file: tgrafconf - file: node_config {% for script in TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]] %} - file: tgraf_sync_script_{{script}} {% endfor %} - - require: + - require: + - file: trusttheca + - x509: telegraf_crt + - x509: telegraf_key - file: tgrafconf - file: node_config - {% if GLOBALS.role in ['so-manager', 'so-eval', 'so-managersearch' ] %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - - x509: influxdb_crt - - x509: influxdb_key delete_so-telegraf_so-status.disabled: file.uncomment: diff --git a/salt/telegraf/etc/telegraf.conf b/salt/telegraf/etc/telegraf.conf index d2cb87057..aafcf6d77 100644 --- a/salt/telegraf/etc/telegraf.conf +++ b/salt/telegraf/etc/telegraf.conf @@ -7,6 +7,7 @@ {%- set UNIQUEID = salt['pillar.get']('sensor:uniqueid', '') %} {%- set ZEEK_ENABLED = salt['pillar.get']('zeek:enabled', True) %} {%- set MDENGINE = GLOBALS.md_engine %} +{%- set LOGSTASH_ENABLED = LOGSTASH_MERGED.enabled %} # Global tags can be specified here in key="value" format. [global_tags] role = "{{ GLOBALS.role.split('-') | last }}" @@ -55,9 +56,9 @@ ## Logging configuration: ## Run telegraf with debug log messages. - debug = {{ TELEGRAFMERGED.config.debug }} + debug = {{ 'true' if TELEGRAFMERGED.config.debug else 'false' }} ## Run telegraf in quiet mode (error log messages only). - quiet = false + quiet = {{ 'true' if TELEGRAFMERGED.config.quiet else 'false'}} ## Specify the log file name. The empty string means to log to stderr. logfile = "/var/log/telegraf/telegraf.log" @@ -241,12 +242,8 @@ # ## Use TLS but skip chain & host verification # # insecure_skip_verify = false -{%- set logstash_metrics_roles = ['so-searchnode','so-standalone','so-managersearch','so-heavynode'] %} -{%- if GLOBALS.pipeline != "KAFKA" %} -{%- set logstash_metrics_roles = logstash_metrics_roles + ['so-manager', 'so-receiver'] %} -{%- endif %} - -{%- if grains.role in logstash_metrics_roles %} +{#- Fleet nodes do not have pillar access to logstash credentials #} +{%- if LOGSTASH_ENABLED and grains.role != 'so-fleet' %} [[inputs.logstash]] url = "http://localhost:9600" collect = ["pipelines"] diff --git a/salt/telegraf/map.jinja b/salt/telegraf/map.jinja index 1d92b8b5b..fe2625bbc 100644 --- a/salt/telegraf/map.jinja +++ b/salt/telegraf/map.jinja @@ -14,13 +14,6 @@ {% do TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]].remove('zeekloss.sh') %} {% do TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]].remove('zeekcaptureloss.sh') %} {% endif %} - -{% from 'pcap/config.map.jinja' import PCAPMERGED %} -{# PCAPMERGED.enabled is set false in soc ui or if suricata is the pcap engine #} -{% if not PCAPMERGED.enabled %} -{% do TELEGRAFMERGED.scripts[GLOBALS.role.split('-')[1]].remove('stenoloss.sh') %} -{% endif %} - {% endif %} {% if GLOBALS.pipeline != 'REDIS' %} diff --git a/salt/telegraf/scripts/agentstatus.sh b/salt/telegraf/scripts/agentstatus.sh index 718f0e5ce..9a79e2237 100644 --- a/salt/telegraf/scripts/agentstatus.sh +++ b/salt/telegraf/scripts/agentstatus.sh @@ -20,13 +20,14 @@ if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then OFFLINE=$(cat $LOGFILE | grep -wF offline | awk '{print $2}' | tr -d ',') UPDATING=$(cat $LOGFILE | grep -wF updating | awk '{print $2}' | tr -d ',') UNENROLLED=$(cat $LOGFILE | grep -wF unenrolled | awk '{print $2}' | tr -d ',') - OTHER=$(cat $LOGFILE | grep -wF other | awk '{print $2}' | tr -d ',') - EVENTS=$(cat $LOGFILE | grep -wF events | awk '{print $2}' | tr -d ',') - TOTAL=$(cat $LOGFILE | grep -wF total | awk '{print $2}' | tr -d ',') + ORPHANED=$(cat $LOGFILE | grep -wF orphaned | awk '{print $2}' | tr -d ',') + UNINSTALLED=$(cat $LOGFILE | grep -wF uninstalled | awk '{print $2}' | tr -d ',') ALL=$(cat $LOGFILE | grep -wF all | awk '{print $2}' | tr -d ',') ACTIVE=$(cat $LOGFILE | grep -wF active | awk '{print $2}' | tr -d ',') + OTHER=$(cat $LOGFILE | grep -wF other | awk '{print $2}' | tr -d ',') + EVENTS=$(cat $LOGFILE | grep -wF events | awk '{print $2}' | tr -d ',') - echo "agentstatus online=$ONLINE,error=$ERROR,inactive=$INACTIVE,offline=$OFFLINE,updating=$UPDATING,unenrolled=$UNENROLLED,other=$OTHER,events=$EVENTS,total=$TOTAL,all=$ALL,active=$ACTIVE" + echo "agentstatus online=$ONLINE,error=$ERROR,inactive=$INACTIVE,offline=$OFFLINE,updating=$UPDATING,unenrolled=$UNENROLLED,orphaned=$ORPHANED,uninstalled=$UNINSTALLED,all=$ALL,active=$ACTIVE,other=$OTHER,events=$EVENTS" fi fi diff --git a/salt/telegraf/scripts/oldpcap.sh b/salt/telegraf/scripts/oldpcap.sh index 876ff7835..7da5f10f7 100644 --- a/salt/telegraf/scripts/oldpcap.sh +++ b/salt/telegraf/scripts/oldpcap.sh @@ -5,11 +5,7 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{%- if GLOBALS.pcap_engine in ["SURICATA", "TRANSITION"] %} PCAPLOC=/host/nsm/suripcap -{%- else %} -PCAPLOC=/host/nsm/pcap -{%- endif %} # if this script isn't already running if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then diff --git a/salt/telegraf/scripts/stenoloss.sh b/salt/telegraf/scripts/stenoloss.sh deleted file mode 100644 index 5219dcfd0..000000000 --- a/salt/telegraf/scripts/stenoloss.sh +++ /dev/null @@ -1,39 +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. - - - -# if this script isn't already running -if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then - - CHECKIT=$(grep "Thread 0 stats" /var/log/stenographer/stenographer.log |tac |head -2|wc -l) - STENOGREP=$(grep "Thread 0 stats" /var/log/stenographer/stenographer.log |tac |head -2) - - declare RESULT=($STENOGREP) - - CURRENT_PACKETS=$(echo ${RESULT[9]} | awk -F'=' '{print $2 }') - CURRENT_DROPS=$(echo ${RESULT[12]} | awk -F'=' '{print $2 }') - PREVIOUS_PACKETS=$(echo ${RESULT[23]} | awk -F'=' '{print $2 }') - PREVIOUS_DROPS=$(echo ${RESULT[26]} | awk -F'=' '{print $2 }') - - DROPPED=$((CURRENT_DROPS - PREVIOUS_DROPS)) - TOTAL_CURRENT=$((CURRENT_PACKETS + CURRENT_DROPS)) - TOTAL_PAST=$((PREVIOUS_PACKETS + PREVIOUS_DROPS)) - TOTAL=$((TOTAL_CURRENT - TOTAL_PAST)) - - if [ $CHECKIT == 2 ]; then - if [ $DROPPED == 0 ]; then - echo "stenodrop drop=$DROPPED" - else - LOSS=$(echo "4 k $DROPPED $TOTAL / 100 * p" | dc) - echo "stenodrop drop=$LOSS" - fi - fi - -fi - -exit 0 diff --git a/salt/telegraf/soc_telegraf.yaml b/salt/telegraf/soc_telegraf.yaml index b54913da7..40ae7fed8 100644 --- a/salt/telegraf/soc_telegraf.yaml +++ b/salt/telegraf/soc_telegraf.yaml @@ -1,55 +1,56 @@ telegraf: - enabled: + enabled: description: Enables the grid metrics collection process. WARNING - Security Onion grid health monitoring requires this process to remain enabled. Disabling it will cause unexpected and unsupported results. + forcedType: bool advanced: True - helpLink: influxdb.html + helpLink: influxdb config: interval: description: Data collection interval. global: True - helpLink: influxdb.html + helpLink: influxdb metric_batch_size: description: Data collection batch size. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb metric_buffer_limit: description: Data collection buffer size. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb collection_jitter: description: Jitter of the flush interval. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb flush_interval: description: Flush interval for all outputs. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb flush_jitter: description: Jitter the flush interval. global: True advanced: True - helpLink: influxdb.html + helpLink: influxdb debug: - description: Data collection interval. - global: True + description: Run telegraf with debug log messages + forcedType: bool advanced: True - helpLink: influxdb.html + helpLink: influxdb quiet: - description: Data collection interval. - global: True + description: Run telegraf in quiet mode (error log messages only). + forcedType: bool advanced: True - helpLink: influxdb.html + helpLink: influxdb scripts: eval: &telegrafscripts description: List of input.exec scripts to run for this node type. The script must be present in salt/telegraf/scripts. forcedType: "[]string" multiline: True advanced: True - helpLink: influxdb.html + helpLink: influxdb standalone: *telegrafscripts manager: *telegrafscripts managersearch: *telegrafscripts diff --git a/salt/telegraf/ssl.sls b/salt/telegraf/ssl.sls new file mode 100644 index 000000000..c222f5cda --- /dev/null +++ b/salt/telegraf/ssl.sls @@ -0,0 +1,55 @@ +# 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.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'ca/map.jinja' import CA %} + +telegraf_key: + x509.private_key_managed: + - name: /etc/pki/telegraf.key + - keysize: 4096 + - backup: True + - new: True + {% if salt['file.file_exists']('/etc/pki/telegraf.key') -%} + - prereq: + - x509: /etc/pki/telegraf.crt + {%- endif %} + - retry: + attempts: 5 + interval: 30 + +# Create a cert for the talking to telegraf +telegraf_crt: + x509.certificate_managed: + - name: /etc/pki/telegraf.crt + - ca_server: {{ CA.server }} + - signing_policy: influxdb + - private_key: /etc/pki/telegraf.key + - CN: {{ GLOBALS.hostname }} + - subjectAltName: DNS:{{ GLOBALS.hostname }}, IP:{{ GLOBALS.node_ip }} + - days_remaining: 7 + - days_valid: 820 + - backup: True + - timeout: 30 + - retry: + attempts: 5 + interval: 30 + +telegraf_key_perms: + file.managed: + - replace: False + - name: /etc/pki/telegraf.key + - mode: 640 + - group: 939 + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/top.sls b/salt/top.sls index d80806564..c7c6aa65d 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -37,6 +37,7 @@ base: 'not ( *_manager* or *_eval or *_import or *_standalone ) and G@saltversion:{{saltversion}}': - match: compound - salt.minion + - ca - patch.os.schedule - motd - salt.minion-check @@ -49,6 +50,7 @@ base: '( *_manager* or *_eval or *_import or *_standalone ) and G@saltversion:{{saltversion}} and not I@node_data:False': - match: compound - salt.minion + - ca - patch.os.schedule - motd - salt.minion-check @@ -61,8 +63,6 @@ base: - match: compound - salt.master - sensor - - ca - - ssl - registry - manager - backup.config_backup @@ -78,21 +78,18 @@ base: - elasticsearch - elastic-fleet-package-registry - kibana - - pcap - suricata - zeek - strelka - - curator.disabled - elastalert - utility - elasticfleet + - pcap.cleanup '*_standalone and G@saltversion:{{saltversion}} and not I@node_data:False': - match: compound - salt.master - sensor - - ca - - ssl - registry - manager - backup.config_backup @@ -110,22 +107,19 @@ base: - redis - elastic-fleet-package-registry - kibana - - pcap - suricata - zeek - strelka - - curator.disabled - elastalert - utility - elasticfleet - stig - kafka + - pcap.cleanup '*_manager or *_managerhype and G@saltversion:{{saltversion}} and not I@node_data:False': - match: compound - salt.master - - ca - - ssl - registry - nginx - influxdb @@ -143,7 +137,6 @@ base: - redis - elastic-fleet-package-registry - kibana - - curator.disabled - elastalert - utility - elasticfleet @@ -157,8 +150,6 @@ base: '*_managersearch and G@saltversion:{{saltversion}} and not I@node_data:False': - match: compound - salt.master - - ca - - ssl - registry - nginx - influxdb @@ -174,7 +165,6 @@ base: - elasticsearch - logstash - redis - - curator.disabled - elastic-fleet-package-registry - kibana - elastalert @@ -187,8 +177,6 @@ base: - match: compound - salt.master - sensor - - ca - - ssl - registry - manager - nginx @@ -200,7 +188,6 @@ base: - sensoroni - telegraf - firewall - - pcap - elasticsearch - elastic-fleet-package-registry - kibana @@ -208,11 +195,11 @@ base: - suricata - zeek - elasticfleet + - pcap.cleanup '*_searchnode and G@saltversion:{{saltversion}}': - match: compound - firewall - - ssl - elasticsearch - logstash - sensoroni @@ -225,23 +212,21 @@ base: '*_sensor and G@saltversion:{{saltversion}}': - match: compound - sensor - - ssl - sensoroni - telegraf - firewall - nginx - - pcap - suricata - healthcheck - zeek - strelka - elasticfleet.install_agent_grid - stig + - pcap.cleanup '*_heavynode and G@saltversion:{{saltversion}}': - match: compound - sensor - - ssl - sensoroni - telegraf - nginx @@ -249,17 +234,15 @@ base: - elasticsearch - logstash - redis - - curator.disabled - strelka - - pcap - suricata - zeek - elasticfleet.install_agent_grid - elasticagent + - pcap.cleanup '*_receiver and G@saltversion:{{saltversion}}': - match: compound - - ssl - sensoroni - telegraf - firewall @@ -271,7 +254,6 @@ base: '*_idh and G@saltversion:{{saltversion}}': - match: compound - - ssl - sensoroni - telegraf - firewall @@ -280,7 +262,6 @@ base: '*_fleet and G@saltversion:{{saltversion}}': - match: compound - - ssl - sensoroni - telegraf - firewall @@ -293,7 +274,6 @@ base: '*_hypervisor and I@features:vrt and G@saltversion:{{saltversion}}': - match: compound - - ssl - sensoroni - telegraf - firewall @@ -304,7 +284,6 @@ base: - stig '*_desktop and G@saltversion:{{saltversion}}': - - ssl - sensoroni - telegraf - elasticfleet.install_agent_grid diff --git a/salt/vars/globals.map.jinja b/salt/vars/globals.map.jinja index ca75437eb..385db02ae 100644 --- a/salt/vars/globals.map.jinja +++ b/salt/vars/globals.map.jinja @@ -1,5 +1,5 @@ {% import 'vars/init.map.jinja' as INIT %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} {% from 'global/map.jinja' import GLOBALMERGED %} {% from 'vars/' ~ INIT.GRAINS.role.split('-')[1] ~ '.map.jinja' import ROLE_GLOBALS %} {# role is so-role so we have to split off the 'so' #} @@ -25,8 +25,8 @@ 'pcap_engine': GLOBALMERGED.pcapengine, 'pipeline': GLOBALMERGED.pipeline, 'so_version': INIT.PILLAR.global.soversion, - 'so_docker_gateway': DOCKER.gateway, - 'so_docker_range': DOCKER.range, + 'so_docker_gateway': DOCKERMERGED.gateway, + 'so_docker_range': DOCKERMERGED.range, 'url_base': INIT.PILLAR.global.url_base, 'so_model': INIT.GRAINS.get('sosmodel',''), 'sensoroni_key': INIT.PILLAR.sensoroni.config.sensoronikey, diff --git a/salt/versionlock/init.sls b/salt/versionlock/init.sls index a310356b4..e2ee77347 100644 --- a/salt/versionlock/init.sls +++ b/salt/versionlock/init.sls @@ -3,7 +3,7 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% if grains.os_family == 'Debian' or (grains.os_family == 'RedHat' and salt['pkg.version']('python3-dnf-plugin-versionlock') != "") %} +{% if salt['pkg.version']('python3-dnf-plugin-versionlock') != "" %} {% from 'versionlock/map.jinja' import VERSIONLOCKMERGED %} {% for pkg in VERSIONLOCKMERGED.hold %} {{pkg}}_held: diff --git a/salt/versionlock/map.jinja b/salt/versionlock/map.jinja index 1477657bc..75d8a1b97 100644 --- a/salt/versionlock/map.jinja +++ b/salt/versionlock/map.jinja @@ -6,11 +6,7 @@ {% import_yaml 'versionlock/defaults.yaml' as VERSIONLOCKDEFAULTS %} {% set VERSIONLOCKMERGED = salt['pillar.get']('versionlock', VERSIONLOCKDEFAULTS.versionlock, merge=True) %} -{% if grains.os_family == 'RedHat' %} -{% set HELD = salt['pkg.list_holds']() %} -{% else %} -{% set HELD = salt['pkg.get_selections'](state='hold')['hold'] %} -{% endif %} +{% set HELD = salt['pkg.list_holds']() %} {# these are packages held / versionlock in other states #} {% set PACKAGES_HELD_IN_OTHER_STATES = [ diff --git a/salt/versionlock/soc_versionlock.yaml b/salt/versionlock/soc_versionlock.yaml index 92fd69875..5249d972a 100644 --- a/salt/versionlock/soc_versionlock.yaml +++ b/salt/versionlock/soc_versionlock.yaml @@ -4,4 +4,4 @@ versionlock: global: True forcedType: "[]string" multiline: True - helpLink: versionlock.html + helpLink: soup#holding-os-updates diff --git a/salt/zeek/config.sls b/salt/zeek/config.sls index 42ea74fc9..3677b1ba1 100644 --- a/salt/zeek/config.sls +++ b/salt/zeek/config.sls @@ -32,6 +32,16 @@ zeekpolicydir: - group: 939 - makedirs: True +zeekzkgsync: + file.recurse: + - name: /opt/so/conf/zeek/zkg + - source: salt://zeek/zkg + - user: 937 + - group: 939 + - clean: True + - makedirs: True + - exclude_pat: README + # Zeek Log Directory zeeklogdir: file.directory: @@ -156,6 +166,9 @@ zeekja4cfg: - source: salt://zeek/files/config.zeek.ja4 - user: 937 - group: 939 + - template: jinja + - defaults: + JA4PLUS: {{ ZEEKMERGED.ja4plus.enabled }} # BPF compilation failed {% if ZEEKBPF and not ZEEK_BPF_STATUS %} diff --git a/salt/zeek/defaults.yaml b/salt/zeek/defaults.yaml index 169b6521a..4058b01b8 100644 --- a/salt/zeek/defaults.yaml +++ b/salt/zeek/defaults.yaml @@ -1,5 +1,7 @@ zeek: enabled: False + ja4plus: + enabled: False config: node: lb_procs: 0 diff --git a/salt/zeek/enabled.sls b/salt/zeek/enabled.sls index ff090428f..ee78714c8 100644 --- a/salt/zeek/enabled.sls +++ b/salt/zeek/enabled.sls @@ -6,7 +6,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'docker/docker.map.jinja' import DOCKERMERGED %} include: @@ -18,9 +18,12 @@ so-zeek: - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-zeek:{{ GLOBALS.so_version }} - start: True - privileged: True + {% if DOCKERMERGED.containers['so-zeek'].ulimits %} - ulimits: - - core=0 - - nofile=1048576:1048576 + {% for ULIMIT in DOCKERMERGED.containers['so-zeek'].ulimits %} + - {{ ULIMIT.name }}={{ ULIMIT.soft }}:{{ ULIMIT.hard }} + {% endfor %} + {% endif %} - binds: - /nsm/zeek/logs:/nsm/zeek/logs:rw - /nsm/zeek/spool:/nsm/zeek/spool:rw @@ -35,21 +38,22 @@ so-zeek: - /opt/so/conf/zeek/policy/intel:/opt/zeek/share/zeek/policy/intel:rw - /opt/so/conf/zeek/bpf:/opt/zeek/etc/bpf:ro - /opt/so/conf/zeek/config.zeek:/opt/zeek/share/zeek/site/packages/ja4/config.zeek:ro - {% if DOCKER.containers['so-zeek'].custom_bind_mounts %} - {% for BIND in DOCKER.containers['so-zeek'].custom_bind_mounts %} + - /opt/so/conf/zeek/zkg:/opt/so/conf/zeek/zkg:ro + {% if DOCKERMERGED.containers['so-zeek'].custom_bind_mounts %} + {% for BIND in DOCKERMERGED.containers['so-zeek'].custom_bind_mounts %} - {{ BIND }} {% endfor %} {% endif %} - network_mode: host - {% if DOCKER.containers['so-zeek'].extra_hosts %} + {% if DOCKERMERGED.containers['so-zeek'].extra_hosts %} - extra_hosts: - {% for XTRAHOST in DOCKER.containers['so-zeek'].extra_hosts %} + {% for XTRAHOST in DOCKERMERGED.containers['so-zeek'].extra_hosts %} - {{ XTRAHOST }} {% endfor %} {% endif %} - {% if DOCKER.containers['so-zeek'].extra_env %} + {% if DOCKERMERGED.containers['so-zeek'].extra_env %} - environment: - {% for XTRAENV in DOCKER.containers['so-zeek'].extra_env %} + {% for XTRAENV in DOCKERMERGED.containers['so-zeek'].extra_env %} - {{ XTRAENV }} {% endfor %} {% endif %} diff --git a/salt/zeek/files/config.zeek.ja4 b/salt/zeek/files/config.zeek.ja4 index 3d0035481..7bde4da3c 100644 --- a/salt/zeek/files/config.zeek.ja4 +++ b/salt/zeek/files/config.zeek.ja4 @@ -8,20 +8,20 @@ export { option JA4_raw: bool = F; # FoxIO license required for JA4+ - option JA4S_enabled: bool = F; + option JA4S_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; option JA4S_raw: bool = F; - option JA4D_enabled: bool = F; + option JA4D_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; - option JA4H_enabled: bool = F; + option JA4H_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; option JA4H_raw: bool = F; - option JA4L_enabled: bool = F; - - option JA4SSH_enabled: bool = F; + option JA4L_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; - option JA4T_enabled: bool = F; - option JA4TS_enabled: bool = F; + option JA4SSH_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; - option JA4X_enabled: bool = F; + option JA4T_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; + option JA4TS_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; + + option JA4X_enabled: bool = {{ 'T' if JA4PLUS else 'F' }}; } diff --git a/salt/zeek/soc_zeek.yaml b/salt/zeek/soc_zeek.yaml index 929b9debd..a14594635 100644 --- a/salt/zeek/soc_zeek.yaml +++ b/salt/zeek/soc_zeek.yaml @@ -1,28 +1,35 @@ zeek: enabled: description: Controls whether the Zeek (network packet inspection) process runs. Disabling this process could result in loss of network protocol metadata. If Suricata was selected as the protocol metadata engine during setup then this will already be disabled. - helpLink: zeek.html + forcedType: bool + helpLink: zeek + ja4plus: + enabled: + description: "Enables JA4+ fingerprinting (JA4S, JA4D, JA4H, JA4L, JA4SSH, JA4T, JA4TS, JA4X). By enabling this, you agree to the terms of the JA4+ license [https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE-JA4](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE-JA4)." + forcedType: bool + helpLink: zeek + advanced: False config: local: load: description: Contains a list of policies and scripts loaded by Zeek. Values in the Current Grid Value dialog box apply to every instance of Zeek. Values in a dialog box for a specific node will only apply to that node. forcedType: "[]string" - helpLink: zeek.html + helpLink: zeek load-sigs: description: Contains a list of signatures loaded by Zeek. Values placed in the Current Grid Value dialog box apply to every instance of Zeek. Values placed in a dialog box for a specific node will only apply to that node. forcedType: "[]string" - helpLink: zeek.html + helpLink: zeek redef: description: List of Zeek variables to redefine. Values placed in the Current Grid Value dialog box apply to every instance of Zeek. Values placed in a dialog box for a specific node will only apply to that node. forcedType: "[]string" advanced: True - helpLink: zeek.html + helpLink: zeek networks: HOME_NET: description: List of IP or CIDR blocks to define as the HOME_NET. forcedType: "[]string" advanced: False - helpLink: zeek.html + helpLink: zeek multiline: True regex: ^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\/([0-9]|[1-2][0-9]|3[0-2]))?$|^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?))|:))|(([0-9A-Fa-f]{1,4}:){5}((:[0-9A-Fa-f]{1,4}){1,2}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){4}((:[0-9A-Fa-f]{1,4}){1,3}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){3}((:[0-9A-Fa-f]{1,4}){1,4}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){2}((:[0-9A-Fa-f]{1,4}){1,5}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(([0-9A-Fa-f]{1,4}:){1}((:[0-9A-Fa-f]{1,4}){1,6}|:((25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)\.){3}(25[0-5]|(2[0-4]|1[0-9])[0-9]|0?[0-9][0-9]?)|:))|(:((:[0-9A-Fa-f]{1,4}){1,7}|:)))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$ regexFailureMessage: You must enter a valid IP address or CIDR. @@ -30,13 +37,13 @@ zeek: lb_procs: description: Contains the number of CPU cores or workers used by Zeek. This setting should only be applied to individual nodes and will be ignored if CPU affinity is enabled. title: workers - helpLink: zeek.html + helpLink: zeek node: True pins_enabled: description: Enabling this setting allows you to pin Zeek to specific CPUs. title: cpu affinity enabled forcedType: bool - helpLink: zeek.html + helpLink: zeek node: True advanced: True pins: @@ -44,61 +51,61 @@ zeek: title: cpu affinity multiline: True forcedType: "[]string" - helpLink: zeek.html + helpLink: zeek node: True advanced: True zeekctl: CompressLogs: description: This setting enables compression of Zeek logs. If you are seeing packet loss at the top of the hour in Zeek or PCAP you might need to disable this by seting it to 0. This will use more disk space but save IO and CPU. - helpLink: zeek.html + helpLink: zeek policy: custom: filters: conn: description: Conn Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True duplicates: True dns: description: DNS Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True duplicates: True files: description: Files Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True duplicates: True httphost: description: HTTP Hosts Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True duplicates: True httpuri: description: HTTP URI Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True duplicates: True ssl: description: SSL Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True duplicates: True tunnel: description: Tunnel Filter for Zeek. This is an advanced setting and will take further action to enable. - helpLink: zeek.html + helpLink: zeek file: True global: True advanced: True @@ -106,4 +113,4 @@ zeek: file_extraction: description: Contains a list of file or MIME types Zeek will extract from the network streams. Values must adhere to the following format - {"MIME_TYPE":"FILE_EXTENSION"} forcedType: "[]{}" - helpLink: zeek.html + helpLink: zeek diff --git a/salt/zeek/zkg/README b/salt/zeek/zkg/README new file mode 100644 index 000000000..6c3b65ae7 --- /dev/null +++ b/salt/zeek/zkg/README @@ -0,0 +1 @@ +# Place custom Zeek packages in /opt/so/saltstack/local/salt/zeek/zkg/ diff --git a/setup/so-functions b/setup/so-functions index b93c01715..bf95ea9d8 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -852,74 +852,14 @@ detect_cloud() { detect_os() { title "Detecting Base OS" - 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 - not_supported=true - unset is_supported - elif grep -q "CentOS Stream release 9" /etc/redhat-release; then - OS=centos - OSVER=9 - is_centos=true - is_rpm=true - not_supported=true - unset is_supported - elif grep -q "AlmaLinux release 9" /etc/redhat-release; then - OS=alma - OSVER=9 - is_alma=true - is_rpm=true - not_supported=true - unset is_supported - elif grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release; then - if [ -f /etc/oracle-release ]; then - OS=oracle - OSVER=9 - is_oracle=true - is_rpm=true - is_supported=true - else - OS=rhel - OSVER=9 - is_rhel=true - is_rpm=true - not_supported=true - unset is_supported - fi - fi - 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 - not_supported=true - unset is_supported - elif grep -q "UBUNTU_CODENAME=jammy" /etc/os-release; then - OSVER=jammy - UBVER=22.04 - OS=ubuntu - is_ubuntu=true - is_deb=true - not_supported=true - unset is_supported - elif grep -q "VERSION_CODENAME=bookworm" /etc/os-release; then - OSVER=bookworm - DEBVER=12 - is_debian=true - OS=debian - is_deb=true - not_supported=true - unset is_supported - fi - installer_prereq_packages - + if [ -f /etc/redhat-release ] && grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release && [ -f /etc/oracle-release ]; then + OS=oracle + OSVER=9 + is_oracle=true + is_rpm=true + is_supported=true else - info "We were unable to determine if you are using a supported OS." + info "This OS is not supported. Security Onion requires Oracle Linux 9." fail_setup fi @@ -932,23 +872,6 @@ download_elastic_agent_artifacts() { fi } -installer_prereq_packages() { - if [[ $is_deb ]]; then - # Print message to stdout so the user knows setup is doing something - info "Running apt-get update" - retry 150 10 "apt-get update" "" "Err:" >> "$setup_log" 2>&1 || fail_setup - # Install network manager so we can do interface stuff - if ! command -v nmcli > /dev/null 2>&1; then - info "Installing network-manager" - retry 150 10 "apt-get -y install network-manager ethtool" >> "$setup_log" 2>&1 || fail_setup - logCmd "systemctl enable NetworkManager" - logCmd "systemctl start NetworkManager" - fi - if ! command -v curl > /dev/null 2>&1; then - retry 150 10 "apt-get -y install curl" >> "$setup_log" 2>&1 || fail_setup - fi - fi -} disable_auto_start() { @@ -1121,16 +1044,6 @@ generate_ca() { logCmd "openssl x509 -in /etc/pki/ca.crt -noout -subject -issuer -dates" } -generate_ssl() { - # if the install type is a manager then we need to wait for the minion to be ready before trying - # to run the ssl state since we need the minion to sign the certs - if [[ $waitforstate ]]; then - (wait_for_salt_minion "$MINION_ID" "5" '/dev/stdout' || fail_setup) 2>&1 | tee -a "$setup_log" - fi - info "Applying SSL state" - logCmd "salt-call state.apply ssl -l info" -} - generate_passwords(){ title "Generate Random Passwords" INFLUXPASS=$(get_random_value) @@ -1376,9 +1289,6 @@ create_global() { echo " mdengine: 'ZEEK'" >> $global_pillar_file echo " ids: 'Suricata'" >> $global_pillar_file echo " url_base: '$REDIRECTIT'" >> $global_pillar_file - if [[ $HIGHLANDER == 'True' ]]; then - echo " highlander: True" >> $global_pillar_file - fi if [[ $is_airgap ]]; then echo " airgap: True" >> $global_pillar_file else @@ -1392,9 +1302,7 @@ create_global() { echo " registry_host: '$HOSTNAME'" >> $global_pillar_file echo " endgamehost: '$ENDGAMEHOST'" >> $global_pillar_file - if [[ $is_standalone || $is_eval ]]; then - echo " pcapengine: SURICATA" >> $global_pillar_file - fi + echo " pcapengine: SURICATA" >> $global_pillar_file } create_sensoroni_pillar() { @@ -1456,7 +1364,7 @@ make_some_dirs() { mkdir -p $local_salt_dir/salt/firewall/portgroups mkdir -p $local_salt_dir/salt/firewall/ports - for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idh elastalert stig global kafka versionlock hypervisor vm; do + for THEDIR in bpf elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idh elastalert stig global kafka versionlock hypervisor vm; do mkdir -p $local_salt_dir/pillar/$THEDIR touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls touch $local_salt_dir/pillar/$THEDIR/soc_$THEDIR.sls @@ -1472,7 +1380,7 @@ network_init() { title "Initializing Network" disable_ipv6 set_hostname - if [[ ( $is_iso || $is_desktop_iso || $is_debian ) ]]; then + if [[ ( $is_iso || $is_desktop_iso ) ]]; then set_management_interface fi } @@ -1610,7 +1518,6 @@ reserve_group_ids() { logCmd "groupadd -g 940 suricata" logCmd "groupadd -g 948 elastic-agent-pr" logCmd "groupadd -g 949 elastic-agent" - logCmd "groupadd -g 941 stenographer" logCmd "groupadd -g 947 elastic-fleet" logCmd "groupadd -g 960 kafka" } @@ -1644,7 +1551,7 @@ reinstall_init() { { # remove all of root's cronjobs - logCmd "crontab -r -u root" + crontab -r -u root if command -v salt-call &> /dev/null && grep -q "master:" /etc/salt/minion 2> /dev/null; then # Disable schedule so highstate doesn't start running during the install @@ -1654,8 +1561,7 @@ reinstall_init() { salt-call -l info saltutil.kill_all_jobs --local fi - logCmd "salt-call state.apply ca.remove -linfo --local --file-root=../salt" - logCmd "salt-call state.apply ssl.remove -linfo --local --file-root=../salt" + salt-call state.apply ca.remove -linfo --local --file-root=../salt # Kill any salt processes (safely) for service in "${salt_services[@]}"; do @@ -1668,7 +1574,7 @@ reinstall_init() { local count=0 while check_service_status "$service"; do if [[ $count -gt $service_retry_count ]]; then - info "Could not stop $service after 1 minute, exiting setup." + echo "Could not stop $service after 1 minute, exiting setup." # Stop the systemctl process trying to kill the service, show user a message, then exit setup kill -9 $pid @@ -1706,12 +1612,7 @@ reinstall_init() { backup_dir /nsm/influxdb "$date_string" # Uninstall local Elastic Agent, if installed - logCmd "elastic-agent uninstall -f" - - if [[ $is_deb ]]; then - info "Unholding previously held packages." - apt-mark unhold $(apt-mark showhold) - fi + elastic-agent uninstall -f } >> "$setup_log" 2>&1 @@ -1729,11 +1630,7 @@ reset_proxy() { [[ -f /etc/gitconfig ]] && rm -f /etc/gitconfig - if [[ $is_rpm ]]; then - sed -i "/proxy=/d" /etc/dnf/dnf.conf - else - [[ -f /etc/apt/apt.conf.d/00-proxy.conf ]] && rm -f /etc/apt/apt.conf.d/00-proxy.conf - fi + sed -i "/proxy=/d" /etc/dnf/dnf.conf } restore_file() { @@ -1779,14 +1676,8 @@ drop_install_options() { remove_package() { local package_name=$1 - if [[ $is_rpm ]]; then - if rpm -qa | grep -q "$package_name"; then - logCmd "dnf remove -y $package_name" - fi - else - if dpkg -l | grep -q "$package_name"; then - retry 150 10 "apt purge -y \"$package_name\"" - fi + if rpm -qa | grep -q "$package_name"; then + logCmd "dnf remove -y $package_name" fi } @@ -1800,122 +1691,91 @@ remove_package() { securityonion_repo() { # Remove all the current repos - if [[ $is_oracle ]]; then - logCmd "dnf -v clean all" - logCmd "mkdir -vp /root/oldrepos" - if [ -n "$(ls -A /etc/yum.repos.d/ 2>/dev/null)" ]; then - logCmd "mv -v /etc/yum.repos.d/* /root/oldrepos/" - fi - if ! $is_desktop_grid; then - gpg_rpm_import - if [[ ! $is_airgap ]]; then - echo "https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9" > /etc/yum/mirror.txt - echo "https://so-repo-east.s3.us-east-005.backblazeb2.com/prod/2.4/oracle/9" >> /etc/yum/mirror.txt - echo "[main]" > /etc/yum.repos.d/securityonion.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo - echo "installonly_limit=3" >> /etc/yum.repos.d/securityonion.repo - echo "clean_requirements_on_remove=True" >> /etc/yum.repos.d/securityonion.repo - echo "best=True" >> /etc/yum.repos.d/securityonion.repo - echo "skip_if_unavailable=False" >> /etc/yum.repos.d/securityonion.repo - echo "cachedir=/opt/so/conf/reposync/cache" >> /etc/yum.repos.d/securityonion.repo - echo "keepcache=0" >> /etc/yum.repos.d/securityonion.repo - echo "[securityonionsync]" >> /etc/yum.repos.d/securityonion.repo - echo "name=Security Onion Repo repo" >> /etc/yum.repos.d/securityonion.repo - echo "mirrorlist=file:///etc/yum/mirror.txt" >> /etc/yum.repos.d/securityonion.repo - echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo - logCmd "dnf repolist" - else - echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo - echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo - echo "baseurl=https://$MSRV/repo" >> /etc/yum.repos.d/securityonion.repo - echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo - echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo - logCmd "dnf repolist" - fi - elif [[ ! $waitforstate ]]; then + logCmd "dnf -v clean all" + logCmd "mkdir -vp /root/oldrepos" + if [ -n "$(ls -A /etc/yum.repos.d/ 2>/dev/null)" ]; then + logCmd "mv -v /etc/yum.repos.d/* /root/oldrepos/" + fi + if ! $is_desktop_grid; then + gpg_rpm_import + if [[ ! $is_airgap ]]; then + echo "https://repo.securityonion.net/file/so-repo/prod/3/oracle/9" > /etc/yum/mirror.txt + echo "https://so-repo-east.s3.us-east-005.backblazeb2.com/prod/3/oracle/9" >> /etc/yum/mirror.txt + echo "[main]" > /etc/yum.repos.d/securityonion.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo + echo "installonly_limit=3" >> /etc/yum.repos.d/securityonion.repo + echo "clean_requirements_on_remove=True" >> /etc/yum.repos.d/securityonion.repo + echo "best=True" >> /etc/yum.repos.d/securityonion.repo + echo "skip_if_unavailable=False" >> /etc/yum.repos.d/securityonion.repo + echo "cachedir=/opt/so/conf/reposync/cache" >> /etc/yum.repos.d/securityonion.repo + echo "keepcache=0" >> /etc/yum.repos.d/securityonion.repo + echo "[securityonionsync]" >> /etc/yum.repos.d/securityonion.repo + echo "name=Security Onion Repo repo" >> /etc/yum.repos.d/securityonion.repo + echo "mirrorlist=file:///etc/yum/mirror.txt" >> /etc/yum.repos.d/securityonion.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo + logCmd "dnf repolist" + else echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo echo "baseurl=https://$MSRV/repo" >> /etc/yum.repos.d/securityonion.repo echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo - echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo - elif [[ $waitforstate ]]; then - echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo - echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo - echo "baseurl=file:///nsm/repo/" >> /etc/yum.repos.d/securityonion.repo - echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo - echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo + echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo + logCmd "dnf repolist" fi + elif [[ ! $waitforstate ]]; then + echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo + echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo + echo "baseurl=https://$MSRV/repo" >> /etc/yum.repos.d/securityonion.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo + echo "sslverify=0" >> /etc/yum.repos.d/securityonion.repo + elif [[ $waitforstate ]]; then + echo "[securityonion]" > /etc/yum.repos.d/securityonion.repo + echo "name=Security Onion Repo" >> /etc/yum.repos.d/securityonion.repo + echo "baseurl=file:///nsm/repo/" >> /etc/yum.repos.d/securityonion.repo + echo "enabled=1" >> /etc/yum.repos.d/securityonion.repo + echo "gpgcheck=1" >> /etc/yum.repos.d/securityonion.repo fi - if [[ $is_rpm ]]; then logCmd "dnf repolist all"; fi + logCmd "dnf repolist all" if [[ $waitforstate ]]; then - if [[ $is_rpm ]]; then - # Build the repo locally so we can use it - echo "Syncing Repos" - repo_sync_local - fi + # Build the repo locally so we can use it + echo "Syncing Repos" + repo_sync_local fi } repo_sync_local() { SALTVERSION=$(grep "version:" ../salt/salt/master.defaults.yaml | grep -o "[0-9]\+\.[0-9]\+") info "Repo Sync" - if [[ $is_supported ]]; then - # Sync the repo from the the SO repo locally. - # Check for reposync - info "Adding Repo Download Configuration" - mkdir -p /nsm/repo - mkdir -p /opt/so/conf/reposync/cache - echo "https://repo.securityonion.net/file/so-repo/prod/2.4/oracle/9" > /opt/so/conf/reposync/mirror.txt - echo "https://repo-alt.securityonion.net/prod/2.4/oracle/9" >> /opt/so/conf/reposync/mirror.txt - echo "[main]" > /opt/so/conf/reposync/repodownload.conf - echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf - echo "installonly_limit=3" >> /opt/so/conf/reposync/repodownload.conf - echo "clean_requirements_on_remove=True" >> /opt/so/conf/reposync/repodownload.conf - echo "best=True" >> /opt/so/conf/reposync/repodownload.conf - echo "skip_if_unavailable=False" >> /opt/so/conf/reposync/repodownload.conf - echo "cachedir=/opt/so/conf/reposync/cache" >> /opt/so/conf/reposync/repodownload.conf - echo "keepcache=0" >> /opt/so/conf/reposync/repodownload.conf - echo "[securityonionsync]" >> /opt/so/conf/reposync/repodownload.conf - echo "name=Security Onion Repo repo" >> /opt/so/conf/reposync/repodownload.conf - echo "mirrorlist=file:///opt/so/conf/reposync/mirror.txt" >> /opt/so/conf/reposync/repodownload.conf - echo "enabled=1" >> /opt/so/conf/reposync/repodownload.conf - echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf - - logCmd "dnf repolist" - - if [[ ! $is_airgap ]]; then - curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install - retry 5 60 "dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionsync --download-metadata -p /nsm/repo/" >> "$setup_log" 2>&1 || fail_setup - # After the download is complete run createrepo - create_repo - fi - else - # Add the proper repos for unsupported stuff - echo "Adding Repos" - if [[ $is_rpm ]]; then - if [[ $is_rhel ]]; then - logCmd "subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms" - info "Install epel for rhel" - logCmd "dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm" - logCmd "dnf -y install https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm" - else - logCmd "dnf config-manager --set-enabled crb" - logCmd "dnf -y install epel-release" - fi - dnf install -y yum-utils device-mapper-persistent-data lvm2 - curl -fsSL https://repo.securityonion.net/file/so-repo/prod/2.4/so/so.repo | tee /etc/yum.repos.d/so.repo - rpm --import https://packages.broadcom.com/artifactory/api/security/keypair/SaltProjectKey/public - dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo - curl -fsSL "https://github.com/saltstack/salt-install-guide/releases/latest/download/salt.repo" | tee /etc/yum.repos.d/salt.repo - dnf repolist - curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install - else - echo "Not sure how you got here." - exit 1 - fi + # Sync the repo from the SO repo locally. + info "Adding Repo Download Configuration" + mkdir -p /nsm/repo + mkdir -p /opt/so/conf/reposync/cache + echo "https://repo.securityonion.net/file/so-repo/prod/3/oracle/9" > /opt/so/conf/reposync/mirror.txt + echo "https://repo-alt.securityonion.net/prod/3/oracle/9" >> /opt/so/conf/reposync/mirror.txt + echo "[main]" > /opt/so/conf/reposync/repodownload.conf + echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf + echo "installonly_limit=3" >> /opt/so/conf/reposync/repodownload.conf + echo "clean_requirements_on_remove=True" >> /opt/so/conf/reposync/repodownload.conf + echo "best=True" >> /opt/so/conf/reposync/repodownload.conf + echo "skip_if_unavailable=False" >> /opt/so/conf/reposync/repodownload.conf + echo "cachedir=/opt/so/conf/reposync/cache" >> /opt/so/conf/reposync/repodownload.conf + echo "keepcache=0" >> /opt/so/conf/reposync/repodownload.conf + echo "[securityonionsync]" >> /opt/so/conf/reposync/repodownload.conf + echo "name=Security Onion Repo repo" >> /opt/so/conf/reposync/repodownload.conf + echo "mirrorlist=file:///opt/so/conf/reposync/mirror.txt" >> /opt/so/conf/reposync/repodownload.conf + echo "enabled=1" >> /opt/so/conf/reposync/repodownload.conf + echo "gpgcheck=1" >> /opt/so/conf/reposync/repodownload.conf + + logCmd "dnf repolist" + + if [[ ! $is_airgap ]]; then + curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install + retry 5 60 "dnf reposync --norepopath -g --delete -m -c /opt/so/conf/reposync/repodownload.conf --repoid=securityonionsync --download-metadata -p /nsm/repo/" >> "$setup_log" 2>&1 || fail_setup + # After the download is complete run createrepo + create_repo fi } @@ -1923,57 +1783,13 @@ saltify() { SALTVERSION=$(grep "version:" ../salt/salt/master.defaults.yaml | grep -o "[0-9]\+\.[0-9]\+") info "Installing Salt $SALTVERSION" chmod u+x ../salt/salt/scripts/bootstrap-salt.sh - if [[ $is_deb ]]; then - DEBIAN_FRONTEND=noninteractive retry 30 10 "apt-get -y -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" upgrade" >> "$setup_log" 2>&1 || fail_setup - if [ $OSVER == "focal" ]; then update-alternatives --install /usr/bin/python python /usr/bin/python3.10 10; fi - local pkg_arr=( - 'apache2-utils' - 'ca-certificates' - 'curl' - 'software-properties-common' - 'apt-transport-https' - 'openssl' - 'netcat-openbsd' - 'jq' - 'gnupg' - ) - retry 30 10 "apt-get -y install ${pkg_arr[*]}" || fail_setup - - logCmd "mkdir -vp /etc/apt/keyrings" - logCmd "wget -q --inet4-only -O /etc/apt/keyrings/docker.pub https://download.docker.com/linux/ubuntu/gpg" - - if [[ $is_ubuntu ]]; then - # Add Docker Repo - add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" - - else - # Add Docker Repo - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg - echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $OSVER stable" > /etc/apt/sources.list.d/docker.list - fi - - logCmd "apt-key add /etc/apt/keyrings/docker.pub" - - retry 30 10 "apt-get update" "" "Err:" || fail_setup - if [[ $waitforstate ]]; then - retry 30 10 "bash ../salt/salt/scripts/bootstrap-salt.sh -M -X stable $SALTVERSION" || fail_setup - retry 30 10 "apt-mark hold salt-minion salt-common salt-master" || fail_setup - retry 30 10 "apt-get -y install python3-pip python3-dateutil python3-m2crypto python3-packaging python3-influxdb python3-lxml" || exit 1 - else - retry 30 10 "bash ../salt/salt/scripts/bootstrap-salt.sh -X stable $SALTVERSION" || fail_setup - retry 30 10 "apt-mark hold salt-minion salt-common" || fail_setup - fi - fi - - if [[ $is_rpm ]]; then - if [[ $waitforstate ]]; then - # install all for a manager - retry 30 10 "bash ../salt/salt/scripts/bootstrap-salt.sh -r -M -X stable $SALTVERSION" || fail_setup - else - # just a minion - retry 30 10 "bash ../salt/salt/scripts/bootstrap-salt.sh -r -X stable $SALTVERSION" || fail_setup - fi + if [[ $waitforstate ]]; then + # install all for a manager + retry 30 10 "bash ../salt/salt/scripts/bootstrap-salt.sh -r -M -X stable $SALTVERSION" || fail_setup + else + # just a minion + retry 30 10 "bash ../salt/salt/scripts/bootstrap-salt.sh -r -X stable $SALTVERSION" || fail_setup fi salt_install_module_deps @@ -2119,14 +1935,7 @@ set_proxy() { "}" > /root/.docker/config.json # Set proxy for package manager - if [[ $is_rpm ]]; then - echo "proxy=$so_proxy" >> /etc/yum.conf - else - # Set it up so the updates roll through the manager - printf '%s\n'\ - "Acquire::http::Proxy \"$so_proxy\";"\ - "Acquire::https::Proxy \"$so_proxy\";" > /etc/apt/apt.conf.d/00-proxy.conf - fi + echo "proxy=$so_proxy" >> /etc/yum.conf # Set global git proxy printf '%s\n'\ @@ -2316,23 +2125,13 @@ update_sudoers_for_testing() { } update_packages() { - if [[ $is_oracle ]]; then - logCmd "dnf repolist" - logCmd "dnf -y update --allowerasing --exclude=salt*,docker*,containerd*" - RMREPOFILES=("oracle-linux-ol9.repo" "uek-ol9.repo" "virt-ol9.repo") - info "Removing repo files added by oracle-repos package update" - for FILE in ${RMREPOFILES[@]}; do - logCmd "rm -f /etc/yum.repos.d/$FILE" - done - elif [[ $is_deb ]]; then - info "Running apt-get update" - retry 150 10 "apt-get -y update" "" "Err:" >> "$setup_log" 2>&1 || fail_setup - info "Running apt-get upgrade" - retry 150 10 "apt-get -y upgrade" >> "$setup_log" 2>&1 || fail_setup - else - info "Updating packages" - logCmd "dnf -y update --allowerasing --exclude=salt*,docker*,containerd*" - fi + logCmd "dnf repolist" + logCmd "dnf -y update --allowerasing --exclude=salt*,docker*,containerd*" + RMREPOFILES=("oracle-linux-ol9.repo" "uek-ol9.repo" "virt-ol9.repo") + info "Removing repo files added by oracle-repos package update" + for FILE in ${RMREPOFILES[@]}; do + logCmd "rm -f /etc/yum.repos.d/$FILE" + done } # This is used for development to speed up network install tests. @@ -2342,15 +2141,7 @@ use_turbo_proxy() { return fi - if [[ $OS == 'centos' ]]; then - printf '%s\n' "proxy=${TURBO}:3142" >> /etc/yum.conf - else - printf '%s\n'\ - "Acquire {"\ - " HTTP::proxy \"${TURBO}:3142\";"\ - " HTTPS::proxy \"${TURBO}:3142\";"\ - "}" > /etc/apt/apt.conf.d/proxy.conf - fi + printf '%s\n' "proxy=${TURBO}:3142" >> /etc/yum.conf } wait_for_file() { diff --git a/setup/so-preflight b/setup/so-preflight deleted file mode 100755 index 151651077..000000000 --- a/setup/so-preflight +++ /dev/null @@ -1,213 +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. - - -cd "$(dirname "$0")" || exit 255 - -source ../salt/common/tools/sbin/so-common -source ./so-functions - -script_run="$1" - -retry_count=10 -retry_sleep=5 -warning_prefix="[WARNING]" -info_prefix="[INFO ]" -error_prefix="[ERROR ]" - -if [[ $script_run == true ]]; then - preflight_log="${2:-'/root/preflight.log'}" -else - preflight_log='/root/preflight.log' -fi - -check_default_repos() { - local ret_code=0 - local repo_str=' Checking OS default repos with ' - if [[ $script_run == true ]]; then - printf '%s' "$repo_str" - else - printf '%s' "$repo_str" | tee -a "$preflight_log" - fi - - if [[ $OS == 'centos' ]]; then - if [[ $script_run == true ]]; then - printf '%s' 'yum update.' - else - printf '%s' 'yum update.' | tee -a "$preflight_log" - fi - echo "" >> "$preflight_log" - yum -y check-update >> $preflight_log 2>&1 - ret_code=$? - if [[ $ret_code == 0 || $ret_code == 100 ]]; then - printf '%s\n' ' SUCCESS' - ret_code=0 - else - printf '%s\n' ' FAILURE' - fi - else - if [[ $script_run == true ]]; then - printf '%s' 'apt update.' - else - printf '%s' 'apt update.' | tee -a "$preflight_log" - fi - echo "" >> "$preflight_log" - retry 150 10 "apt-get -y update" >> $preflight_log 2>&1 - ret_code=$? - [[ $ret_code == 0 ]] && printf '%s\n' ' SUCCESS' || printf '%s\n' ' FAILURE' - - fi - - return $ret_code -} - -check_new_repos() { - local repo_url_str=' Checking repo URLs added by setup.' - if [[ $script_run == true ]]; then - printf '%s' "$repo_url_str" - else - printf '%s' "$repo_url_str" | tee -a "$preflight_log" - fi - - if [[ $OS == 'centos' ]]; then - local repo_arr=( - "https://download.docker.com/linux/centos/docker-ce.repo" - "https://repo.securityonion.net/file/securityonion-repo/keys/SALTSTACK-GPG-KEY.pub" - "https://download.docker.com/linux/ubuntu/gpg" - ) - else - local ubuntu_version - ubuntu_version=$(grep VERSION_ID /etc/os-release 2> /dev/null | awk -F '[ "]' '{print $2}') - local repo_arr=( - "https://download.docker.com/linux/ubuntu/gpg" - "https://download.docker.com/linux/ubuntu" - "https://repo.securityonion.net/file/securityonion-repo/ubuntu/$ubuntu_version/amd64/salt/SALTSTACK-GPG-KEY.pub" - ) - fi - - __check_url_arr "${repo_arr[@]}" - local ret_code=$? - [[ $ret_code == 0 ]] && printf '%s\n' ' SUCCESS' || printf '%s\n' ' FAILURE' - return $ret_code -} - -check_misc_urls() { - local misc_url_str=' Checking various other URLs used by setup.' - if [[ $script_run == true ]]; then - printf '%s' "$misc_url_str" - else - printf '%s' "$misc_url_str" | tee -a "$preflight_log" - fi - - local so_version - so_version=$(cat ../VERSION) - local url_arr=( - "https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/master/KEYS" - "https://github.com/Neo23x0/signature-base" - "https://sigs.securityonion.net/$so_version/securityonion-$so_version.iso.sig" - "https://ghcr.io/" - "https://rules.emergingthreats.net/open/" - "https://rules.emergingthreatspro.com/" - ) - - __check_url_arr "${url_arr[@]}" - local ret_code=$? - [[ $ret_code == 0 ]] && printf '%s\n' ' SUCCESS' || printf '%s\n' ' FAILURE' - return $ret_code -} - -__check_url_arr() { - local ret_code=0 - echo "" >> "$preflight_log" - for url in "$@"; do - # Reset vars - local status=999 # Set status to something outside the range of normal HTTP codes but above the 200 range - local ret=1 - local count=0 - - while [[ $ret != 0 && $count -lt $retry_count ]]; do - ((count++)) - [[ $count != 1 ]] && sleep $retry_sleep - status=$(curl -s -o /dev/null -w "%{http_code}" -L "$url" 2> /dev/null) - ret=$? - local count_str - printf -v count_str '%02d' "$count" - [[ $ret != 0 ]] && echo "$warning_prefix ($count_str/$retry_count) Could not reach $url, curl error code: $ret" >> "$preflight_log" - done - - if [[ $ret == 0 ]]; then - url_success_str="Successfully reached $url" - if [[ $status -ge 400 ]]; then - echo "$warning_prefix $url_success_str but server responded with HTTP code $status." >> "$preflight_log" - else - printf '%s\n' "$info_prefix $url_success_str" >> "$preflight_log" - fi - else - ret_code=1 - echo "$error_prefix Could not reach $url after $retry_count attempts." >> "$preflight_log" - fi - done - echo "" >> "$preflight_log" - return $ret_code -} - -preflight_prereqs() { - local ret_code=0 - - if [[ $OS == 'centos' ]]; then - : # no-op to match structure of other checks for $OS var - else - retry 150 10 "apt-get -y install curl" >> "$preflight_log" 2>&1 || ret_code=1 - fi - - return $ret_code -} - -main() { - local intro_str="Beginning pre-flight checks." - local success_str="Pre-flight checks completed successfully!" - local fail_str="Pre-flight checks could not complete." - - [[ -f $preflight_log ]] || touch "$preflight_log" - - detect_os "$preflight_log" - - if [[ $script_run == true ]]; then - echo "$intro_str" - else - echo "$intro_str" | tee "$preflight_log" - fi - - check_default_repos &&\ - preflight_prereqs &&\ - check_new_repos &&\ - check_misc_urls - - local success=$? - - echo "" - if [[ $success == 0 ]]; then - if [[ $script_run == true ]]; then - echo "$success_str" - else - echo "$success_str" | tee -a "$preflight_log" - echo "" - fi - else - if [[ $script_run == true ]]; then - echo "$fail_str" - else - echo "$fail_str" | tee -a "$preflight_log" - echo "Check $preflight_log for details." - echo "" - fi - fi - - exit $success -} - -main diff --git a/setup/so-setup b/setup/so-setup index d09e8fc35..823a379df 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -66,36 +66,6 @@ set_timezone # Let's see what OS we are dealing with here detect_os -# Ubuntu/Debian whiptail pallete to make it look the same as CentOS and Rocky. -set_palette >> $setup_log 2>&1 - -if [[ $not_supported ]] && [ -z "$test_profile" ]; then - if [[ "$OSVER" == "focal" ]]; then - if (whiptail_focal_warning); then - true - else - info "User cancelled setup." - whiptail_cancel - fi - else - if (whiptail_unsupported_os_warning); then - true - else - info "User cancelled setup." - whiptail_cancel - fi - fi -fi - -# we need to upgrade packages on debian prior to install and reboot if there are due to iptables-restore not running properly -# if packages are updated and the box isn't rebooted -if [[ $is_debian ]]; then - update_packages - if [[ -f "/var/run/reboot-required" ]] && [ -z "$test_profile" ]; then - whiptail_debian_reboot_required - reboot - fi -fi # Check to see if this is the setup type of "desktop". is_desktop= @@ -108,7 +78,7 @@ if [ "$setup_type" = 'desktop' ]; then fi fi -# Make sure if ISO is specified that we are dealing with CentOS or Rocky +# Make sure if ISO is specified that we are dealing with an RPM-based install title "Detecting if this is an ISO install" if [[ "$setup_type" == 'iso' ]]; then if [[ $is_rpm ]]; then @@ -773,12 +743,9 @@ if ! [[ -f $install_opt_file ]]; then # wait here until we get a response from the salt-master since it may have just restarted # exit setup after 5-6 minutes of trying check_salt_master_status || fail "Can't access salt master or it is not ready" - # apply the ca state to create the ca and put it in the mine early in the install + # apply the ca state to create the ca and symlink to local/salt/ca/files/ca.crt # the minion ip will already be in the mine from configure_minion function in so-functions generate_ca - # this will also call the ssl state since docker requires the intca - # the salt-minion service will need to be up on the manager to sign requests - generate_ssl logCmd "salt-call state.apply docker" firewall_generate_templates set_initial_firewall_policy @@ -802,14 +769,6 @@ if ! [[ -f $install_opt_file ]]; then logCmd "salt-call state.apply influxdb -l info" logCmd "salt-call state.highstate -l info" logCmd "salt-call schedule.disable -linfo --local" - if [[ ! $is_airgap ]]; then - title "Downloading IDS Rules" - logCmd "so-rule-update" - if [[ $monints || $is_import ]]; then - title "Applying the Suricata state to load the new rules" - logCmd "salt-call state.apply suricata -l info" - fi - fi if [[ $is_airgap ]]; then title "Syncing AI-Generated Detection Summaries" airgap_detection_summaries @@ -831,6 +790,11 @@ if ! [[ -f $install_opt_file ]]; then fi checkin_at_boot set_initial_firewall_access + initialize_elasticsearch_indices "so-case so-casehistory so-assistant-session so-assistant-chat" + # run a final highstate before enabling scheduled highstates. + # this will ensure so-elasticsearch-ilm-policy-load and so-elasticsearch-templates-load have a chance to run after elasticfleet is setup + info "Running final highstate for setup" + logCmd "salt-call state.highstate -l info" logCmd "salt-call schedule.enable -linfo --local" verify_setup else diff --git a/setup/so-verify b/setup/so-verify index f99c6e418..8d23275ea 100755 --- a/setup/so-verify +++ b/setup/so-verify @@ -69,6 +69,8 @@ log_has_errors() { grep -vE "Running scope as unit" | \ grep -vE "securityonion-resources/sigma/stable" | \ grep -vE "remove_failed_vm.sls" | \ + grep -vE "failed to copy: httpReadSeeker" | \ + grep -vE "Error response from daemon: failed to resolve reference" | \ grep -vE "log-.*-pipeline_failed_attempts" &> "$error_log" if [[ $? -eq 0 ]]; then diff --git a/setup/so-whiptail b/setup/so-whiptail index 6fc5cbba5..9a1d21150 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -14,7 +14,7 @@ whiptail_airgap() { [[ $is_manager || $is_import ]] && node_str='manager' INTERWEBS=$(whiptail --title "$whiptail_title" --menu \ - "How should this $node_str be installed?\n\nFor more information, please see:\n$DOC_BASE_URL/airgap.html" 13 70 2 \ + "How should this $node_str be installed?\n\nFor more information, please see:\n$DOC_BASE_URL/airgap" 13 70 2 \ "Standard " "This $node_str has access to the Internet" \ "Airgap " "This $node_str does not have access to the Internet" 3>&1 1>&2 2>&3 ) @@ -27,23 +27,6 @@ whiptail_airgap() { fi } -whiptail_debian_reboot_required() { - - [ -n "$TESTING" ] && return - - read -r -d '' message <<- EOM - - Packages were upgraded and a reboot is required prior to Security Onion installation. - - Once the reboot has completed, rerun Security Onion setup. - - Press TAB and then the ENTER key to reboot the system. - - EOM - - whiptail --title "$whiptail_title" --msgbox "$message" 24 75 --scrolltext -} - whiptail_desktop_install() { [ -n "$TESTING" ] && return @@ -156,7 +139,7 @@ whiptail_accept_telemetry() { Adjust this setting at anytime via the SOC Configuration screen. - Documentation: https://docs.securityonion.net/en/2.4/telemetry.html + Documentation: https://securityonion.net/docs/telemetry Enable SOC Telemetry to help improve future releases? EOM @@ -289,7 +272,7 @@ whiptail_storage_requirements() { You need ${needed_val} to meet minimum requirements. - Visit $DOC_BASE_URL/hardware.html for more information. + Visit $DOC_BASE_URL/hardware for more information. Select YES to continue anyway, or select NO to cancel. EOM @@ -496,27 +479,6 @@ __append_end_msg() { EOM } -whiptail_focal_warning() { - - [ -n "$TESTING" ] && return - - read -r -d '' focal_warning_continue <<- EOM - - WARNING: Ubuntu 20.04 is only supported as a minion role. - - This node may not install or operate as expected if installed - as a manager, managersearch, standalone, eval, or import. - - Would you like to continue the install? - - EOM - whiptail --title "$whiptail_title" \ - --yesno "$focal_warning_continue" 14 75 --defaultno - - local exitstatus=$? - return $exitstatus - -} whiptail_gauge_post_setup() { @@ -586,23 +548,15 @@ whiptail_install_type() { [ -n "$TESTING" ] && return # What kind of install are we doing? - if [[ "$OSVER" != "focal" ]]; then - install_type=$(whiptail --title "$whiptail_title" --menu \ - "What kind of installation would you like to do?\n\nFor more information, please see:\n$DOC_BASE_URL/architecture.html" 18 65 5 \ - "IMPORT" "Import PCAP or log files " \ - "EVAL" "Evaluation mode (not for production) " \ - "STANDALONE" "Standalone production install " \ - "DISTRIBUTED" "Distributed deployment " \ - "DESKTOP" "Security Onion Desktop" \ - 3>&1 1>&2 2>&3 - ) - elif [[ "$OSVER" == "focal" ]]; then - install_type=$(whiptail --title "$whiptail_title" --menu \ - "What kind of installation would you like to do?\n\nFor more information, please see:\n$DOC_BASE_URL/architecture.html" 18 65 5 \ - "DISTRIBUTED" "Distributed install submenu " \ - 3>&1 1>&2 2>&3 - ) - fi + install_type=$(whiptail --title "$whiptail_title" --menu \ + "What kind of installation would you like to do?\n\nFor more information, please see:\n$DOC_BASE_URL/architecture" 18 65 5 \ + "IMPORT" "Import PCAP or log files " \ + "EVAL" "Evaluation mode (not for production) " \ + "STANDALONE" "Standalone production install " \ + "DISTRIBUTED" "Distributed deployment " \ + "DESKTOP" "Security Onion Desktop" \ + 3>&1 1>&2 2>&3 + ) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -623,18 +577,11 @@ whiptail_install_type_dist() { [ -n "$TESTING" ] && return - if [[ "$OSVER" != "focal" ]]; then dist_option=$(whiptail --title "$whiptail_title" --menu "Do you want to start a new deployment or join this box to \nan existing deployment?" 11 75 2 \ "New Deployment " "Create a new Security Onion deployment" \ "Existing Deployment " "Join to an existing Security Onion deployment " \ 3>&1 1>&2 2>&3 ) - elif [[ "$OSVER" == "focal" ]]; then - dist_option=$(whiptail --title "$whiptail_title" --menu "Since this is Ubuntu, this box can only be connected to \nan existing deployment." 11 75 2 \ - "Existing Deployment " "Join to an existing Security Onion deployment " \ - 3>&1 1>&2 2>&3 - ) - fi local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -649,7 +596,7 @@ whiptail_install_type_dist_new() { read -r -d '' mngr_msg <<- EOM Choose a distributed manager type to start a new grid. - See $DOC_BASE_URL/architecture.html for details. + See $DOC_BASE_URL/architecture for details. Note: MANAGER is the recommended option for most users. MANAGERSEARCH should only be used in very specific situations. EOM @@ -670,7 +617,7 @@ whiptail_install_type_dist_existing() { local node_msg read -r -d '' node_msg <<- EOM - Choose a distributed node type to join to an existing grid. See $DOC_BASE_URL/architecture.html for details. + Choose a distributed node type to join to an existing grid. See $DOC_BASE_URL/architecture for details. Note: Heavy nodes (HEAVYNODE) are NOT recommended for most users. EOM @@ -916,7 +863,7 @@ whiptail_net_method() { [ -n "$TESTING" ] && return local pkg_mngr - if [[ $OS = 'centos' ]]; then pkg_mngr="yum"; else pkg_mngr='apt'; fi + pkg_mngr="yum" read -r -d '' options_msg <<- EOM "Direct" - Internet requests connect directly to the Internet. @@ -1133,25 +1080,11 @@ whiptail_passwords_dont_match() { } -whiptail_preflight_err() { - [ -n "$TESTING" ] && return 1 - - read -r -d '' message <<- EOM - The so-preflight script failed checking one or more URLs required by setup. Check $setup_log for more details. - - Would you like to exit setup? - EOM - - whiptail --title "$whiptail_title" \ - --yesno "$message" 11 75 \ - --yes-button "Continue" --no-button "Exit" --defaultno -} - whiptail_proxy_ask() { [ -n "$TESTING" ] && return local pkg_mngr - if [[ $OS = 'centos' ]]; then pkg_mngr="yum"; else pkg_mngr='apt'; fi + pkg_mngr="yum" whiptail --title "$whiptail_title" --yesno "Do you want to proxy the traffic for git, docker client, wget, curl, ${pkg_mngr}, and various other SO components through a separate server in your environment?" 9 65 --defaultno } @@ -1420,7 +1353,7 @@ whiptail_storage_requirements() { You need ${needed_val} to meet minimum requirements. - Visit $DOC_BASE_URL/hardware.html for more information. + Visit $DOC_BASE_URL/hardware for more information. Select YES to continue anyway, or select NO to cancel. EOM @@ -1434,48 +1367,6 @@ whiptail_storage_requirements() { whiptail_check_exitstatus $exitstatus } -whiptail_ubuntu_notsupported() { - [ -n "$TESTING" ] && return - - read -r -d '' message <<- EOM - Ubuntu is not supported for this node type. - - Please use a supported OS or install via ISO. - EOM - whiptail --title "$whiptail_title" --msgbox "$message" 14 75 -} - -whiptail_ubuntu_warning() { - [ -n "$TESTING" ] && return - - read -r -d '' message <<- EOM - Ubuntu support for this node type is limited. - - Please consider using a fully supported OS or install via ISO. - EOM - whiptail --title "$whiptail_title" --msgbox "$message" 14 75 - -} - -whiptail_unsupported_os_warning() { - - [ -n "$TESTING" ] && return - - read -r -d '' unsupported_os_continue <<- EOM - - WARNING: An unsupported operating system has been detected. - Security Onion may not install or operate as expected. - - Would you like to continue the install? - - EOM - whiptail --title "$whiptail_title" \ - --yesno "$unsupported_os_continue" 14 75 --defaultno - - local exitstatus=$? - return $exitstatus - -} whiptail_uppercase_warning() { diff --git a/sigs/securityonion-2.4.10-20230815.iso.sig b/sigs/securityonion-2.4.10-20230815.iso.sig deleted file mode 100644 index 636dfe63b..000000000 Binary files a/sigs/securityonion-2.4.10-20230815.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.10-20230821.iso.sig b/sigs/securityonion-2.4.10-20230821.iso.sig deleted file mode 100644 index 251032166..000000000 Binary files a/sigs/securityonion-2.4.10-20230821.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.100-20240829.iso.sig b/sigs/securityonion-2.4.100-20240829.iso.sig deleted file mode 100644 index 39db1a63d..000000000 Binary files a/sigs/securityonion-2.4.100-20240829.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.100-20240903.iso.sig b/sigs/securityonion-2.4.100-20240903.iso.sig deleted file mode 100644 index 74f0ecfd7..000000000 Binary files a/sigs/securityonion-2.4.100-20240903.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.110-20241004.iso.sig b/sigs/securityonion-2.4.110-20241004.iso.sig deleted file mode 100644 index 40bc093e2..000000000 Binary files a/sigs/securityonion-2.4.110-20241004.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.110-20241010.iso.sig b/sigs/securityonion-2.4.110-20241010.iso.sig deleted file mode 100644 index 90849a7b6..000000000 Binary files a/sigs/securityonion-2.4.110-20241010.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.111-20241217.iso.sig b/sigs/securityonion-2.4.111-20241217.iso.sig deleted file mode 100644 index e3545c57a..000000000 Binary files a/sigs/securityonion-2.4.111-20241217.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.120-20250212.iso.sig b/sigs/securityonion-2.4.120-20250212.iso.sig deleted file mode 100644 index 54975b60f..000000000 Binary files a/sigs/securityonion-2.4.120-20250212.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.130-20250311.iso.sig b/sigs/securityonion-2.4.130-20250311.iso.sig deleted file mode 100644 index d9f5c6ed9..000000000 Binary files a/sigs/securityonion-2.4.130-20250311.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.140-20250324.iso.sig b/sigs/securityonion-2.4.140-20250324.iso.sig deleted file mode 100644 index ca910c2c2..000000000 Binary files a/sigs/securityonion-2.4.140-20250324.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.141-20250331.iso.sig b/sigs/securityonion-2.4.141-20250331.iso.sig deleted file mode 100644 index 7ced49915..000000000 Binary files a/sigs/securityonion-2.4.141-20250331.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.150-20250512.iso.sig b/sigs/securityonion-2.4.150-20250512.iso.sig deleted file mode 100644 index 7121c68c6..000000000 Binary files a/sigs/securityonion-2.4.150-20250512.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.150-20250522.iso.sig b/sigs/securityonion-2.4.150-20250522.iso.sig deleted file mode 100644 index aecfe4767..000000000 Binary files a/sigs/securityonion-2.4.150-20250522.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.160-20250625.iso.sig b/sigs/securityonion-2.4.160-20250625.iso.sig deleted file mode 100644 index 0145af053..000000000 Binary files a/sigs/securityonion-2.4.160-20250625.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.170-20250812.iso.sig b/sigs/securityonion-2.4.170-20250812.iso.sig deleted file mode 100644 index df29c07b5..000000000 Binary files a/sigs/securityonion-2.4.170-20250812.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.180-20250916.iso.sig b/sigs/securityonion-2.4.180-20250916.iso.sig deleted file mode 100644 index 4ba61d389..000000000 Binary files a/sigs/securityonion-2.4.180-20250916.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.190-20251024.iso.sig b/sigs/securityonion-2.4.190-20251024.iso.sig deleted file mode 100644 index 430c09e47..000000000 Binary files a/sigs/securityonion-2.4.190-20251024.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.20-20231006.iso.sig b/sigs/securityonion-2.4.20-20231006.iso.sig deleted file mode 100644 index b253c6734..000000000 Binary files a/sigs/securityonion-2.4.20-20231006.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.20-20231012.iso.sig b/sigs/securityonion-2.4.20-20231012.iso.sig deleted file mode 100644 index 0704f7d1c..000000000 Binary files a/sigs/securityonion-2.4.20-20231012.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.200-20251216.iso.sig b/sigs/securityonion-2.4.200-20251216.iso.sig deleted file mode 100644 index cc7286fae..000000000 Binary files a/sigs/securityonion-2.4.200-20251216.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.201-20260114.iso.sig b/sigs/securityonion-2.4.201-20260114.iso.sig deleted file mode 100644 index 6a24a3e25..000000000 Binary files a/sigs/securityonion-2.4.201-20260114.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.30-20231113.iso.sig b/sigs/securityonion-2.4.30-20231113.iso.sig deleted file mode 100644 index 1fc98e60a..000000000 Binary files a/sigs/securityonion-2.4.30-20231113.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.30-20231117.iso.sig b/sigs/securityonion-2.4.30-20231117.iso.sig deleted file mode 100644 index debbc8364..000000000 Binary files a/sigs/securityonion-2.4.30-20231117.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.30-20231121.iso.sig b/sigs/securityonion-2.4.30-20231121.iso.sig deleted file mode 100644 index 4feba8dad..000000000 Binary files a/sigs/securityonion-2.4.30-20231121.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.30-20231204.iso.sig b/sigs/securityonion-2.4.30-20231204.iso.sig deleted file mode 100644 index 104472a7b..000000000 Binary files a/sigs/securityonion-2.4.30-20231204.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.30-20231219.iso.sig b/sigs/securityonion-2.4.30-20231219.iso.sig deleted file mode 100644 index 1dc0adcd8..000000000 Binary files a/sigs/securityonion-2.4.30-20231219.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.30-20231228.iso.sig b/sigs/securityonion-2.4.30-20231228.iso.sig deleted file mode 100644 index b49229ac1..000000000 Binary files a/sigs/securityonion-2.4.30-20231228.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.40-20240116.iso.sig b/sigs/securityonion-2.4.40-20240116.iso.sig deleted file mode 100644 index c09de5c9d..000000000 Binary files a/sigs/securityonion-2.4.40-20240116.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.5-20230807.iso.sig b/sigs/securityonion-2.4.5-20230807.iso.sig deleted file mode 100644 index fdf914164..000000000 Binary files a/sigs/securityonion-2.4.5-20230807.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.50-20240220.iso.sig b/sigs/securityonion-2.4.50-20240220.iso.sig deleted file mode 100644 index bb9eac323..000000000 Binary files a/sigs/securityonion-2.4.50-20240220.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.60-20240320.iso.sig b/sigs/securityonion-2.4.60-20240320.iso.sig deleted file mode 100644 index c0129ab64..000000000 Binary files a/sigs/securityonion-2.4.60-20240320.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.70-20240529.iso.sig b/sigs/securityonion-2.4.70-20240529.iso.sig deleted file mode 100644 index c3825eb6e..000000000 Binary files a/sigs/securityonion-2.4.70-20240529.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.80-20240624.iso.sig b/sigs/securityonion-2.4.80-20240624.iso.sig deleted file mode 100644 index a559e9f1a..000000000 Binary files a/sigs/securityonion-2.4.80-20240624.iso.sig and /dev/null differ diff --git a/sigs/securityonion-2.4.90-20240729.iso.sig b/sigs/securityonion-2.4.90-20240729.iso.sig deleted file mode 100644 index 49e5232a3..000000000 Binary files a/sigs/securityonion-2.4.90-20240729.iso.sig and /dev/null differ diff --git a/sigs/securityonion-3.0.0-20260331.iso.sig b/sigs/securityonion-3.0.0-20260331.iso.sig new file mode 100644 index 000000000..a3bc334c1 Binary files /dev/null and b/sigs/securityonion-3.0.0-20260331.iso.sig differ