mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-06 17:22:49 +01:00
Merge pull request #13923 from Security-Onion-Solutions/jertel/wip
Connect API
This commit is contained in:
@@ -49,6 +49,8 @@ base:
|
||||
- kibana.adv_kibana
|
||||
- kratos.soc_kratos
|
||||
- kratos.adv_kratos
|
||||
- hydra.soc_hydra
|
||||
- hydra.adv_hydra
|
||||
- redis.nodes
|
||||
- redis.soc_redis
|
||||
- redis.adv_redis
|
||||
@@ -98,6 +100,7 @@ base:
|
||||
- kibana.secrets
|
||||
{% endif %}
|
||||
- kratos.soc_kratos
|
||||
- kratos.adv_kratos
|
||||
- elasticsearch.soc_elasticsearch
|
||||
- elasticsearch.adv_elasticsearch
|
||||
- elasticfleet.soc_elasticfleet
|
||||
@@ -115,8 +118,8 @@ base:
|
||||
- kibana.adv_kibana
|
||||
- strelka.soc_strelka
|
||||
- strelka.adv_strelka
|
||||
- kratos.soc_kratos
|
||||
- kratos.adv_kratos
|
||||
- hydra.soc_hydra
|
||||
- hydra.adv_hydra
|
||||
- redis.soc_redis
|
||||
- redis.adv_redis
|
||||
- influxdb.soc_influxdb
|
||||
@@ -151,6 +154,8 @@ base:
|
||||
- idstools.adv_idstools
|
||||
- kratos.soc_kratos
|
||||
- kratos.adv_kratos
|
||||
- hydra.soc_hydra
|
||||
- hydra.adv_hydra
|
||||
- redis.nodes
|
||||
- redis.soc_redis
|
||||
- redis.adv_redis
|
||||
@@ -264,6 +269,7 @@ base:
|
||||
- kibana.secrets
|
||||
{% endif %}
|
||||
- kratos.soc_kratos
|
||||
- kratos.adv_kratos
|
||||
- elasticsearch.soc_elasticsearch
|
||||
- elasticsearch.adv_elasticsearch
|
||||
- elasticfleet.soc_elasticfleet
|
||||
@@ -279,8 +285,8 @@ base:
|
||||
- kibana.adv_kibana
|
||||
- backup.soc_backup
|
||||
- backup.adv_backup
|
||||
- kratos.soc_kratos
|
||||
- kratos.adv_kratos
|
||||
- hydra.soc_hydra
|
||||
- hydra.adv_hydra
|
||||
- redis.soc_redis
|
||||
- redis.adv_redis
|
||||
- influxdb.soc_influxdb
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
'influxdb',
|
||||
'soc',
|
||||
'kratos',
|
||||
'hydra',
|
||||
'elasticfleet',
|
||||
'elastic-fleet-package-registry',
|
||||
'firewall',
|
||||
@@ -68,6 +69,7 @@
|
||||
'strelka.manager',
|
||||
'soc',
|
||||
'kratos',
|
||||
'hydra',
|
||||
'influxdb',
|
||||
'telegraf',
|
||||
'firewall',
|
||||
@@ -95,6 +97,7 @@
|
||||
'strelka.manager',
|
||||
'soc',
|
||||
'kratos',
|
||||
'hydra',
|
||||
'elasticfleet',
|
||||
'elastic-fleet-package-registry',
|
||||
'firewall',
|
||||
@@ -117,6 +120,7 @@
|
||||
'strelka.manager',
|
||||
'soc',
|
||||
'kratos',
|
||||
'hydra',
|
||||
'elastic-fleet-package-registry',
|
||||
'elasticfleet',
|
||||
'firewall',
|
||||
@@ -151,6 +155,7 @@
|
||||
'influxdb',
|
||||
'soc',
|
||||
'kratos',
|
||||
'hydra',
|
||||
'elastic-fleet-package-registry',
|
||||
'elasticfleet',
|
||||
'firewall',
|
||||
|
||||
@@ -4,4 +4,5 @@ backup:
|
||||
- /etc/pki
|
||||
- /etc/salt
|
||||
- /nsm/kratos
|
||||
- /nsm/hydra
|
||||
destination: "/nsm/backup"
|
||||
@@ -29,6 +29,7 @@ container_list() {
|
||||
"so-influxdb"
|
||||
"so-kibana"
|
||||
"so-kratos"
|
||||
"so-hydra"
|
||||
"so-nginx"
|
||||
"so-pcaptools"
|
||||
"so-soc"
|
||||
@@ -53,6 +54,7 @@ container_list() {
|
||||
"so-kafka"
|
||||
"so-kibana"
|
||||
"so-kratos"
|
||||
"so-hydra"
|
||||
"so-logstash"
|
||||
"so-nginx"
|
||||
"so-pcaptools"
|
||||
|
||||
@@ -51,6 +51,14 @@ docker:
|
||||
custom_bind_mounts: []
|
||||
extra_hosts: []
|
||||
extra_env: []
|
||||
'so-hydra':
|
||||
final_octet: 30
|
||||
port_bindings:
|
||||
- 0.0.0.0:4444:4444
|
||||
- 0.0.0.0:4445:4445
|
||||
custom_bind_mounts: []
|
||||
extra_hosts: []
|
||||
extra_env: []
|
||||
'so-logstash':
|
||||
final_octet: 29
|
||||
port_bindings:
|
||||
|
||||
@@ -45,6 +45,7 @@ docker:
|
||||
so-influxdb: *dockerOptions
|
||||
so-kibana: *dockerOptions
|
||||
so-kratos: *dockerOptions
|
||||
so-hydra: *dockerOptions
|
||||
so-logstash: *dockerOptions
|
||||
so-nginx: *dockerOptions
|
||||
so-nginx-fleet-node: *dockerOptions
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "log",
|
||||
"version": ""
|
||||
},
|
||||
"name": "hydra-logs",
|
||||
"namespace": "so",
|
||||
"description": "Hydra logs",
|
||||
"policy_id": "so-grid-nodes_general",
|
||||
"inputs": {
|
||||
"logs-logfile": {
|
||||
"enabled": true,
|
||||
"streams": {
|
||||
"log.logs": {
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"force": true
|
||||
}
|
||||
@@ -823,6 +823,116 @@ elasticsearch:
|
||||
priority: 50
|
||||
min_age: 30d
|
||||
warm: 7
|
||||
so-hydra:
|
||||
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
|
||||
- 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:
|
||||
allow_custom_routing: false
|
||||
hidden: false
|
||||
ignore_missing_component_templates: []
|
||||
index_patterns:
|
||||
- logs-hydra-so*
|
||||
priority: 500
|
||||
template:
|
||||
mappings:
|
||||
date_detection: false
|
||||
dynamic_templates:
|
||||
- strings_as_keyword:
|
||||
mapping:
|
||||
ignore_above: 1024
|
||||
type: keyword
|
||||
match_mapping_type: string
|
||||
settings:
|
||||
index:
|
||||
lifecycle:
|
||||
name: so-hydra-logs
|
||||
mapping:
|
||||
total_fields:
|
||||
limit: 5000
|
||||
number_of_replicas: 0
|
||||
number_of_shards: 1
|
||||
refresh_interval: 30s
|
||||
sort:
|
||||
field: '@timestamp'
|
||||
order: desc
|
||||
policy:
|
||||
phases:
|
||||
cold:
|
||||
actions:
|
||||
set_priority:
|
||||
priority: 0
|
||||
min_age: 60d
|
||||
delete:
|
||||
actions:
|
||||
delete: {}
|
||||
min_age: 365d
|
||||
hot:
|
||||
actions:
|
||||
rollover:
|
||||
max_age: 30d
|
||||
max_primary_shard_size: 50gb
|
||||
set_priority:
|
||||
priority: 100
|
||||
min_age: 0ms
|
||||
warm:
|
||||
actions:
|
||||
set_priority:
|
||||
priority: 50
|
||||
min_age: 30d
|
||||
warm: 7
|
||||
so-lists:
|
||||
index_sorting: false
|
||||
index_template:
|
||||
|
||||
9
salt/elasticsearch/files/ingest/hydra
Normal file
9
salt/elasticsearch/files/ingest/hydra
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"description" : "hydra",
|
||||
"processors" : [
|
||||
{"set":{"field":"audience","value":"access","override":false,"ignore_failure":true}},
|
||||
{"set":{"field":"event.dataset","ignore_empty_value":true,"ignore_failure":true,"value":"hydra.{{{audience}}}","media_type":"text/plain"}},
|
||||
{"set":{"field":"event.action","ignore_failure":true,"copy_from":"msg" }},
|
||||
{ "pipeline": { "name": "common" } }
|
||||
]
|
||||
}
|
||||
@@ -545,6 +545,7 @@ elasticsearch:
|
||||
so-suricata_x_alerts: *indexSettings
|
||||
so-import: *indexSettings
|
||||
so-kratos: *indexSettings
|
||||
so-hydra: *indexSettings
|
||||
so-kismet: *indexSettings
|
||||
so-logstash: *indexSettings
|
||||
so-redis: *indexSettings
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
'so-influxdb',
|
||||
'so-kibana',
|
||||
'so-kratos',
|
||||
'so-hydra',
|
||||
'so-nginx',
|
||||
'so-redis',
|
||||
'so-soc',
|
||||
@@ -30,6 +31,7 @@
|
||||
'so-kafka',
|
||||
'so-kibana',
|
||||
'so-kratos',
|
||||
'so-hydra',
|
||||
'so-logstash',
|
||||
'so-nginx',
|
||||
'so-redis',
|
||||
@@ -73,6 +75,7 @@
|
||||
'so-influxdb',
|
||||
'so-kibana',
|
||||
'so-kratos',
|
||||
'so-hydra',
|
||||
'so-nginx',
|
||||
'so-soc'
|
||||
] %}
|
||||
|
||||
51
salt/hydra/config.sls
Normal file
51
salt/hydra/config.sls
Normal file
@@ -0,0 +1,51 @@
|
||||
# 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 "hydra/map.jinja" import HYDRAMERGED %}
|
||||
|
||||
hydradir:
|
||||
file.directory:
|
||||
- name: /nsm/hydra
|
||||
- user: 928
|
||||
- group: 928
|
||||
- mode: 700
|
||||
- makedirs: True
|
||||
|
||||
hydradbdir:
|
||||
file.directory:
|
||||
- name: /nsm/hydra/db
|
||||
- user: 928
|
||||
- group: 928
|
||||
- mode: 700
|
||||
- makedirs: True
|
||||
|
||||
hydralogdir:
|
||||
file.directory:
|
||||
- name: /opt/so/log/hydra
|
||||
- user: 928
|
||||
- group: 928
|
||||
- makedirs: True
|
||||
|
||||
hydraconfig:
|
||||
file.managed:
|
||||
- name: /opt/so/conf/hydra/hydra.yaml
|
||||
- source: salt://hydra/files/hydra.yaml.jinja
|
||||
- user: 928
|
||||
- group: 928
|
||||
- mode: 600
|
||||
- template: jinja
|
||||
- makedirs: True
|
||||
- defaults:
|
||||
HYDRAMERGED: {{ HYDRAMERGED }}
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
30
salt/hydra/defaults.yaml
Normal file
30
salt/hydra/defaults.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
hydra:
|
||||
enabled: False
|
||||
config:
|
||||
serve:
|
||||
public:
|
||||
port: 4444
|
||||
admin:
|
||||
port: 4445
|
||||
urls:
|
||||
self:
|
||||
issuer: https://URL_BASE/connect
|
||||
public: https://URL_BASE/connect
|
||||
admin: http://localhost:4445
|
||||
|
||||
secrets:
|
||||
system: []
|
||||
ttl:
|
||||
access_token: 1h
|
||||
oidc:
|
||||
subject_identifiers:
|
||||
supported_types:
|
||||
- pairwise
|
||||
- public
|
||||
pairwise:
|
||||
salt: ""
|
||||
log:
|
||||
level: debug
|
||||
format: json
|
||||
sqa:
|
||||
opt_out: true
|
||||
27
salt/hydra/disabled.sls
Normal file
27
salt/hydra/disabled.sls
Normal file
@@ -0,0 +1,27 @@
|
||||
# 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:
|
||||
- hydra.sostatus
|
||||
|
||||
so-hydra:
|
||||
docker_container.absent:
|
||||
- force: True
|
||||
|
||||
so-hydra_so-status.disabled:
|
||||
file.comment:
|
||||
- name: /opt/so/conf/so-status/so-status.conf
|
||||
- regex: ^so-hydra$
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
103
salt/hydra/enabled.sls
Normal file
103
salt/hydra/enabled.sls
Normal file
@@ -0,0 +1,103 @@
|
||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
||||
# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at
|
||||
# https://securityonion.net/license; you may not use this file except in compliance with the
|
||||
# Elastic License 2.0.
|
||||
#
|
||||
# Note: Per the Elastic License 2.0, the second limitation states:
|
||||
#
|
||||
# "You may not move, change, disable, or circumvent the license key functionality
|
||||
# in the software, and you may not remove or obscure any functionality in the
|
||||
# software that is protected by the license key."
|
||||
|
||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||
{% if sls.split('.')[0] in allowed_states %}
|
||||
{% from 'docker/docker.map.jinja' import DOCKER %}
|
||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
||||
{% if 'api' in salt['pillar.get']('features', []) %}
|
||||
|
||||
include:
|
||||
- hydra.config
|
||||
- hydra.sostatus
|
||||
|
||||
so-hydra:
|
||||
docker_container.running:
|
||||
- image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-hydra:{{ GLOBALS.so_version }}
|
||||
- hostname: hydra
|
||||
- name: so-hydra
|
||||
- networks:
|
||||
- sobridge:
|
||||
- ipv4_address: {{ DOCKER.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 %}
|
||||
- {{ BIND }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
- port_bindings:
|
||||
{% for BINDING in DOCKER.containers['so-hydra'].port_bindings %}
|
||||
- {{ BINDING }}
|
||||
{% endfor %}
|
||||
{% if DOCKER.containers['so-hydra'].extra_hosts %}
|
||||
- extra_hosts:
|
||||
{% for XTRAHOST in DOCKER.containers['so-hydra'].extra_hosts %}
|
||||
- {{ XTRAHOST }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if DOCKER.containers['so-hydra'].extra_env %}
|
||||
- environment:
|
||||
{% for XTRAENV in DOCKER.containers['so-hydra'].extra_env %}
|
||||
- {{ XTRAENV }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
- restart_policy: unless-stopped
|
||||
- watch:
|
||||
- file: hydraconfig
|
||||
- require:
|
||||
- file: hydraconfig
|
||||
- file: hydralogdir
|
||||
- file: hydradir
|
||||
|
||||
delete_so-hydra_so-status.disabled:
|
||||
file.uncomment:
|
||||
- name: /opt/so/conf/so-status/so-status.conf
|
||||
- regex: ^so-hydra$
|
||||
|
||||
wait_for_hydra:
|
||||
http.wait_for_successful_query:
|
||||
- name: 'http://{{ GLOBALS.manager }}:4444/'
|
||||
- ssl: True
|
||||
- verify_ssl: False
|
||||
- status:
|
||||
- 200
|
||||
- 301
|
||||
- 302
|
||||
- 404
|
||||
- status_type: list
|
||||
- wait_for: 300
|
||||
- request_interval: 10
|
||||
- require:
|
||||
- docker_container: so-hydra
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_no_license_detected:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_no_license_detected
|
||||
- comment:
|
||||
- "This is a feature supported only for customers with a valid license.
|
||||
Contact Security Onion Solutions, LLC via our website at https://securityonionsolutions.com
|
||||
for more information about purchasing a license to enable this feature."
|
||||
include:
|
||||
- hydra.disabled
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
1
salt/hydra/files/hydra.yaml.jinja
Normal file
1
salt/hydra/files/hydra.yaml.jinja
Normal file
@@ -0,0 +1 @@
|
||||
{{ HYDRAMERGED.config | yaml(false) }}
|
||||
13
salt/hydra/init.sls
Normal file
13
salt/hydra/init.sls
Normal file
@@ -0,0 +1,13 @@
|
||||
# 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 'hydra/map.jinja' import HYDRAMERGED %}
|
||||
|
||||
include:
|
||||
{% if HYDRAMERGED.enabled %}
|
||||
- hydra.enabled
|
||||
{% else %}
|
||||
- hydra.disabled
|
||||
{% endif %}
|
||||
13
salt/hydra/map.jinja
Normal file
13
salt/hydra/map.jinja
Normal file
@@ -0,0 +1,13 @@
|
||||
{# 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 'hydra/defaults.yaml' as HYDRADEFAULTS %}
|
||||
|
||||
{% do HYDRADEFAULTS.hydra.config.urls.self.update({'issuer': HYDRADEFAULTS.hydra.config.urls.self.issuer | replace("URL_BASE", GLOBALS.url_base)}) %}
|
||||
{% do HYDRADEFAULTS.hydra.config.urls.self.update({'public': HYDRADEFAULTS.hydra.config.urls.self.public | replace("URL_BASE", GLOBALS.url_base)}) %}
|
||||
{% do HYDRADEFAULTS.hydra.config.urls.self.update({'admin': HYDRADEFAULTS.hydra.config.urls.self.admin | replace("URL_BASE", GLOBALS.url_base)}) %}
|
||||
|
||||
{% set HYDRAMERGED = salt['pillar.get']('hydra', default=HYDRADEFAULTS.hydra, merge=true) %}
|
||||
28
salt/hydra/soc_hydra.yaml
Normal file
28
salt/hydra/soc_hydra.yaml
Normal file
@@ -0,0 +1,28 @@
|
||||
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
|
||||
config:
|
||||
ttl:
|
||||
access_token:
|
||||
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
|
||||
log:
|
||||
level:
|
||||
description: Log level to use for Kratos logs.
|
||||
global: True
|
||||
helpLink: connect.html
|
||||
format:
|
||||
description: Log output format for Kratos logs.
|
||||
global: True
|
||||
helpLink: connect.html
|
||||
secrets:
|
||||
system:
|
||||
description: Secrets used for token generation. Generated during installation.
|
||||
global: True
|
||||
sensitive: True
|
||||
advanced: True
|
||||
forcedType: "[]string"
|
||||
helpLink: connect.html
|
||||
21
salt/hydra/sostatus.sls
Normal file
21
salt/hydra/sostatus.sls
Normal file
@@ -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.
|
||||
|
||||
{% from 'allowed_states.map.jinja' import allowed_states %}
|
||||
{% if sls.split('.')[0] in allowed_states %}
|
||||
|
||||
append_so-hydra_so-status.conf:
|
||||
file.append:
|
||||
- name: /opt/so/conf/so-status/so-status.conf
|
||||
- text: so-hydra
|
||||
- unless: grep -q so-hydra /opt/so/conf/so-status/so-status.conf
|
||||
|
||||
{% else %}
|
||||
|
||||
{{sls}}_state_not_allowed:
|
||||
test.fail_without_changes:
|
||||
- name: {{sls}}_state_not_allowed
|
||||
|
||||
{% endif %}
|
||||
@@ -50,6 +50,10 @@ kratos:
|
||||
ui_url: https://URL_BASE/login/
|
||||
registration:
|
||||
ui_url: https://URL_BASE/login/
|
||||
after:
|
||||
oidc:
|
||||
hooks:
|
||||
- hook: session
|
||||
default_browser_return_url: https://URL_BASE/
|
||||
allowed_return_urls:
|
||||
- http://127.0.0.1
|
||||
|
||||
@@ -40,6 +40,16 @@ logrotate:
|
||||
- extension .log
|
||||
- dateext
|
||||
- dateyesterday
|
||||
/opt/so/log/hydra/*_x_log:
|
||||
- daily
|
||||
- rotate 14
|
||||
- missingok
|
||||
- copytruncate
|
||||
- compress
|
||||
- create
|
||||
- extension .log
|
||||
- dateext
|
||||
- dateyesterday
|
||||
/opt/so/log/kibana/*_x_log:
|
||||
- daily
|
||||
- rotate 14
|
||||
|
||||
@@ -28,6 +28,13 @@ logrotate:
|
||||
multiline: True
|
||||
global: True
|
||||
forcedType: "[]string"
|
||||
"/opt/so/log/hydra/*_x_log":
|
||||
description: List of logrotate options for this file.
|
||||
title: /opt/so/log/hydra/*.log
|
||||
advanced: True
|
||||
multiline: True
|
||||
global: True
|
||||
forcedType: "[]string"
|
||||
"/opt/so/log/kibana/*_x_log":
|
||||
description: List of logrotate options for this file.
|
||||
title: /opt/so/log/kibana/*.log
|
||||
|
||||
@@ -6,6 +6,10 @@ so-user.lock:
|
||||
file.missing:
|
||||
- name: /var/tmp/so-user.lock
|
||||
|
||||
so-client.lock:
|
||||
file.missing:
|
||||
- name: /var/tmp/so-client.lock
|
||||
|
||||
# Must run before elasticsearch docker container is started!
|
||||
sync_es_users:
|
||||
cmd.run:
|
||||
@@ -16,11 +20,13 @@ sync_es_users:
|
||||
- /opt/so/saltstack/local/salt/elasticsearch/files/users
|
||||
- /opt/so/saltstack/local/salt/elasticsearch/files/users_roles
|
||||
- /opt/so/conf/soc/soc_users_roles
|
||||
- /opt/so/conf/soc/soc_clients_roles
|
||||
- show_changes: False
|
||||
- require:
|
||||
- docker_container: so-kratos
|
||||
- http: wait_for_kratos
|
||||
- file: so-user.lock # require so-user.lock file to be missing
|
||||
- file: so-client.lock # require so-client.lock file to be missing
|
||||
|
||||
# we dont want this added too early in setup, so we add the onlyif to verify 'startup_states: highstate'
|
||||
# is in the minion config. That line is added before the final highstate during setup
|
||||
|
||||
411
salt/manager/tools/sbin/so-client
Executable file
411
salt/manager/tools/sbin/so-client
Executable file
@@ -0,0 +1,411 @@
|
||||
#!/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 [[ -f /usr/sbin/so-common ]]; then
|
||||
source /usr/sbin/so-common
|
||||
else
|
||||
source $(dirname $0)/../../../common/tools/sbin/so-common
|
||||
fi
|
||||
|
||||
function usage() {
|
||||
cat <<USAGE_EOF
|
||||
Usage: $0 <operation> [supporting parameters]
|
||||
|
||||
where <operation> is one of the following:
|
||||
|
||||
list: Lists all client IDs and permissions currently defined in the oauth2 system
|
||||
|
||||
add: Adds a new client to the oauth2 system and outputs the generated secret
|
||||
Required parameters:
|
||||
--name <name>
|
||||
Optional parameters:
|
||||
--note <note> (defaults to blank)
|
||||
--json output as JSON
|
||||
|
||||
delete: Deletes a client from the oauth2 system
|
||||
Required parameters:
|
||||
--id <id>
|
||||
|
||||
addperm: Grants a permission to an existing client
|
||||
Required parameters:
|
||||
--id <id>
|
||||
--permission <permission>
|
||||
|
||||
delperm: Removes a permission from an existing client
|
||||
Required parameters:
|
||||
--id <id>
|
||||
--permission <permission>
|
||||
|
||||
update: Updates a client name and note.
|
||||
Required parameters:
|
||||
--id <id>
|
||||
--name <name>
|
||||
--note <note>
|
||||
--searchusername <run-as username>
|
||||
|
||||
generate-secret: Regenerates a client's secret and outputs the new secret.
|
||||
Required parameters:
|
||||
--id <id>
|
||||
Optional parameters:
|
||||
--json output as JSON
|
||||
|
||||
USAGE_EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ $# -lt 1 || $1 == --help || $1 == -h || $1 == -? || $1 == --h ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
operation=$1
|
||||
shift
|
||||
|
||||
searchUsername=__MISSING__
|
||||
note=__MISSING__
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
param=$1
|
||||
shift
|
||||
case "$param" in
|
||||
--id)
|
||||
id=$(echo $1 | sed 's/"/\\"/g')
|
||||
[[ ${#id} -gt 55 ]] && fail "id cannot be longer than 55 characters"
|
||||
shift
|
||||
;;
|
||||
--permission)
|
||||
perm=$(echo $1 | sed 's/"/\\"/g')
|
||||
[[ ${#perm} -gt 50 ]] && fail "permission cannot be longer than 50 characters"
|
||||
shift
|
||||
;;
|
||||
--name)
|
||||
name=$(echo $1 | sed 's/"/\\"/g')
|
||||
[[ ${#name} -gt 50 ]] && fail "name cannot be longer than 50 characters"
|
||||
shift
|
||||
;;
|
||||
--note)
|
||||
note=$(echo $1 | sed 's/"/\\"/g')
|
||||
[[ ${#note} -gt 100 ]] && fail "note cannot be longer than 100 characters"
|
||||
shift
|
||||
;;
|
||||
--searchusername)
|
||||
searchUsername=$(echo $1 | sed 's/"/\\"/g')
|
||||
[[ ${#searchUsername} -gt 50 ]] && fail "search username cannot be longer than 50 characters"
|
||||
shift
|
||||
;;
|
||||
--json)
|
||||
json=1
|
||||
;;
|
||||
*)
|
||||
echo "Encountered unexpected parameter: $param"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
hydraUrl=${HYDRA_URL:-http://127.0.0.1:4445}
|
||||
socRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_clients_roles}
|
||||
soUID=${SOCORE_UID:-939}
|
||||
soGID=${SOCORE_GID:-939}
|
||||
|
||||
function lock() {
|
||||
# Obtain file descriptor lock
|
||||
exec 99>/var/tmp/so-client.lock || fail "Unable to create lock descriptor; if the system was not shutdown gracefully you may need to remove /var/tmp/so-client.lock manually."
|
||||
flock -w 10 99 || fail "Another process is using so-client; if the system was not shutdown gracefully you may need to remove /var/tmp/so-client.lock manually."
|
||||
trap 'rm -f /var/tmp/so-client.lock' EXIT
|
||||
}
|
||||
|
||||
function fail() {
|
||||
msg=$1
|
||||
echo "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function require() {
|
||||
cmd=$1
|
||||
which "$1" 2>&1 > /dev/null
|
||||
[[ $? != 0 ]] && fail "This script requires the following command be installed: ${cmd}"
|
||||
}
|
||||
|
||||
# Verify this environment is capable of running this script
|
||||
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"
|
||||
}
|
||||
|
||||
function createFile() {
|
||||
filename=$1
|
||||
uid=$2
|
||||
gid=$3
|
||||
|
||||
mkdir -p $(dirname "$filename")
|
||||
truncate -s 0 "$filename"
|
||||
chmod 600 "$filename"
|
||||
chown "${uid}:${gid}" "$filename"
|
||||
}
|
||||
|
||||
function ensureRoleFileExists() {
|
||||
if [[ ! -f "$socRolesFile" || ! -s "$socRolesFile" ]]; then
|
||||
# Generate the new roles file
|
||||
rolesTmpFile="${socRolesFile}.tmp"
|
||||
createFile "$rolesTmpFile" "$soUID" "$soGID"
|
||||
|
||||
if [[ -d "$socRolesFile" ]]; then
|
||||
echo "Removing invalid roles directory created by Docker"
|
||||
rm -fr "$socRolesFile"
|
||||
fi
|
||||
mv "${rolesTmpFile}" "${socRolesFile}"
|
||||
fi
|
||||
}
|
||||
|
||||
function listClients() {
|
||||
response=$(curl -Ss -L -f ${hydraUrl}/admin/clients)
|
||||
[[ $? != 0 ]] && fail "Unable to communicate with Hydra"
|
||||
|
||||
clientIds=$(echo "${response}" | jq -r ".[] | .client_id" | sort)
|
||||
for clientId in $clientIds; do
|
||||
perms=$(grep ":$clientId\$" "$socRolesFile" | cut -d: -f1 | tr '\n' ' ')
|
||||
echo "$clientId: $perms"
|
||||
done
|
||||
}
|
||||
|
||||
function addClientPermission() {
|
||||
id=$1
|
||||
perm=$2
|
||||
|
||||
adjustClientPermission "$id" "$perm" "add"
|
||||
}
|
||||
|
||||
function deleteClientPermission() {
|
||||
id=$1
|
||||
perm=$2
|
||||
|
||||
adjustClientPermission "$id" "$perm" "del"
|
||||
}
|
||||
|
||||
function adjustClientPermission() {
|
||||
identityId=$1
|
||||
perm=$2
|
||||
op=$3
|
||||
|
||||
[[ ${identityId} == "" ]] && fail "Client not found"
|
||||
|
||||
ensureRoleFileExists
|
||||
|
||||
filename="$socRolesFile"
|
||||
hasPerm=0
|
||||
grep "^$perm:" "$socRolesFile" | grep -q "$identityId" && hasPerm=1
|
||||
if [[ "$op" == "add" ]]; then
|
||||
if [[ "$hasPerm" == "1" ]]; then
|
||||
echo "Client '$identityId' already has the permission: $perm"
|
||||
return 1
|
||||
else
|
||||
echo "$perm:$identityId" >> "$filename"
|
||||
fi
|
||||
elif [[ "$op" == "del" ]]; then
|
||||
if [[ "$hasPerm" -ne 1 ]]; then
|
||||
fail "Client '$identityId' does not have the permission: $perm"
|
||||
else
|
||||
sed -e "\!^$perm:$identityId\$!d" "$filename" > "$filename.tmp"
|
||||
cat "$filename".tmp > "$filename"
|
||||
rm -f "$filename".tmp
|
||||
fi
|
||||
else
|
||||
fail "Unsupported permission adjustment operation: $op"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function convertNameToId() {
|
||||
name=$1
|
||||
|
||||
name=${name//[^[:alnum:]]/_}
|
||||
echo "socl_$name" | tr '[:upper:]' '[:lower:]'
|
||||
}
|
||||
|
||||
function createClient() {
|
||||
name=$1
|
||||
note=$2
|
||||
|
||||
id=$(convertNameToId "$name")
|
||||
now=$(date -u +%FT%TZ)
|
||||
secret=$(get_random_value)
|
||||
body=$(cat <<EOF
|
||||
{
|
||||
"access_token_strategy": "opaque",
|
||||
"client_id": "$id",
|
||||
"client_secret": "$secret",
|
||||
"client_name": "$name",
|
||||
"grant_types": [ "client_credentials" ],
|
||||
"response_types": [ "code" ],
|
||||
"metadata": {
|
||||
"note": "$note",
|
||||
"searchUsername": ""
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
response=$(curl -Ss -L --fail-with-body -X POST ${hydraUrl}/admin/clients -d "$body")
|
||||
if [[ $? != 0 ]]; then
|
||||
error=$(echo $response | jq .error)
|
||||
fail "Failed to submit request to Hydra: $error"
|
||||
fi
|
||||
}
|
||||
|
||||
function update() {
|
||||
clientId=$1
|
||||
name=$2
|
||||
note=$3
|
||||
username=$4
|
||||
|
||||
body=$(cat <<EOF
|
||||
[
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/client_name",
|
||||
"value": "$name"
|
||||
},
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/metadata",
|
||||
"value": {
|
||||
"note": "$note",
|
||||
"searchUsername": "$username"
|
||||
}
|
||||
}
|
||||
]
|
||||
EOF
|
||||
)
|
||||
|
||||
response=$(curl -Ss -L --fail-with-body -X PATCH ${hydraUrl}/admin/clients/$id -d "$body")
|
||||
if [[ $? != 0 ]]; then
|
||||
error=$(echo $response | jq .error)
|
||||
fail "Failed to submit request to Hydra: $error"
|
||||
fi
|
||||
}
|
||||
|
||||
function generateSecret() {
|
||||
clientId=$1
|
||||
|
||||
secret=$(get_random_value)
|
||||
body=$(cat <<EOF
|
||||
[
|
||||
{
|
||||
"op": "replace",
|
||||
"path": "/client_secret",
|
||||
"value": "$secret"
|
||||
}
|
||||
]
|
||||
EOF
|
||||
)
|
||||
|
||||
response=$(curl -Ss -L --fail-with-body -X PATCH ${hydraUrl}/admin/clients/$id -d "$body")
|
||||
if [[ $? != 0 ]]; then
|
||||
error=$(echo $response | jq .error)
|
||||
fail "Failed to submit request to Hydra: $error"
|
||||
fi
|
||||
}
|
||||
|
||||
function deleteClient() {
|
||||
identityId=$1
|
||||
|
||||
[[ ${identityId} == "" ]] && fail "Client not found"
|
||||
|
||||
response=$(curl -Ss -XDELETE -L --fail-with-body "${hydraUrl}/admin/clients/$identityId")
|
||||
if [[ $? != 0 ]]; then
|
||||
error=$(echo $response | jq .error)
|
||||
fail "Failed to submit request to Hydra: $error"
|
||||
fi
|
||||
|
||||
rolesTmpFile="${socRolesFile}.tmp"
|
||||
createFile "$rolesTmpFile" "$soUID" "$soGID"
|
||||
grep -v "$identityId" "$socRolesFile" > "$rolesTmpFile"
|
||||
cat "$rolesTmpFile" > "$socRolesFile"
|
||||
}
|
||||
|
||||
case "${operation}" in
|
||||
"add")
|
||||
verifyEnvironment
|
||||
[[ "$name" == "" ]] && fail "A short client name must be provided"
|
||||
|
||||
lock
|
||||
createClient "$name" "$note"
|
||||
if [[ "$json" == "1" ]]; then
|
||||
echo "{\"id\":\"$id\",\"secret\":\"$secret\"}"
|
||||
else
|
||||
echo "Successfully added client ID $id with generated secret: $secret"
|
||||
fi
|
||||
;;
|
||||
|
||||
"list")
|
||||
verifyEnvironment
|
||||
listClients
|
||||
;;
|
||||
|
||||
"addperm")
|
||||
verifyEnvironment
|
||||
[[ "$id" == "" ]] && fail "Id must be provided"
|
||||
[[ "$perm" == "" ]] && fail "Permission must be provided"
|
||||
|
||||
lock
|
||||
if addClientPermission "$id" "$perm"; then
|
||||
echo "Successfully added permission to client"
|
||||
fi
|
||||
;;
|
||||
|
||||
"delperm")
|
||||
verifyEnvironment
|
||||
[[ "$id" == "" ]] && fail "Id must be provided"
|
||||
[[ "$perm" == "" ]] && fail "Permission must be provided"
|
||||
|
||||
lock
|
||||
deleteClientPermission "$id" "$perm"
|
||||
echo "Successfully removed permission from client"
|
||||
;;
|
||||
|
||||
"update")
|
||||
verifyEnvironment
|
||||
[[ "$id" == "" ]] && fail "Id must be provided"
|
||||
[[ "$name" == "" ]] && fail "Name must be provided"
|
||||
[[ "$note" == "__MISSING__" ]] && fail "Note must be provided"
|
||||
[[ "$searchUsername" == "__MISSING__" ]] && fail "Search Username must be provided"
|
||||
|
||||
lock
|
||||
update "$id" "$name" "$note" "$searchUsername"
|
||||
echo "Successfully updated client"
|
||||
;;
|
||||
|
||||
"generate-secret")
|
||||
verifyEnvironment
|
||||
[[ "$id" == "" ]] && fail "Id must be provided"
|
||||
|
||||
lock
|
||||
generateSecret "$id"
|
||||
if [[ "$json" == "1" ]]; then
|
||||
echo "{\"secret\":\"$secret\"}"
|
||||
else
|
||||
echo "Successfully generated secret: $secret"
|
||||
fi
|
||||
;;
|
||||
|
||||
"delete")
|
||||
verifyEnvironment
|
||||
[[ "$id" == "" ]] && fail "Id must be provided"
|
||||
|
||||
lock
|
||||
deleteClient "$id"
|
||||
echo "Successfully deleted client."
|
||||
;;
|
||||
*)
|
||||
fail "Unsupported operation: $operation"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -100,23 +100,23 @@ while [[ $# -gt 0 ]]; do
|
||||
shift
|
||||
case "$param" in
|
||||
--email)
|
||||
email=$1
|
||||
email=$(echo $1 | sed 's/"/\\"/g')
|
||||
shift
|
||||
;;
|
||||
--role)
|
||||
role=$1
|
||||
role=$(echo $1 | sed 's/"/\\"/g')
|
||||
shift
|
||||
;;
|
||||
--firstName)
|
||||
firstName=$1
|
||||
firstName=$(echo $1 | sed 's/"/\\"/g')
|
||||
shift
|
||||
;;
|
||||
--lastName)
|
||||
lastName=$1
|
||||
lastName=$(echo $1 | sed 's/"/\\"/g')
|
||||
shift
|
||||
;;
|
||||
--note)
|
||||
note=$1
|
||||
note=$(echo $1 | sed 's/"/\\"/g')
|
||||
shift
|
||||
;;
|
||||
--skip-sync)
|
||||
@@ -357,7 +357,6 @@ function syncElastic() {
|
||||
random_crypt=$(get_random_value 53)
|
||||
user_data_formatted=$(echo "${user_data_formatted}" | sed -r "s/^(.+:)\$/\\1\$2a\$12${random_crypt}/")
|
||||
fi
|
||||
|
||||
echo "${user_data_formatted}" >> "$usersTmpFile"
|
||||
|
||||
# Append the user roles
|
||||
@@ -373,7 +372,6 @@ function syncElastic() {
|
||||
sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" >> "$rolesTmpFile"
|
||||
[[ $? != 0 ]] && fail "Unable to read role identities from database"
|
||||
done < "$socRolesFile"
|
||||
|
||||
else
|
||||
echo "Database file or soc roles file does not exist yet, skipping users export"
|
||||
fi
|
||||
|
||||
@@ -715,6 +715,8 @@ up_to_2.4.110() {
|
||||
}
|
||||
|
||||
up_to_2.4.120() {
|
||||
add_hydra_pillars
|
||||
|
||||
# this is needed for the new versionlock state
|
||||
mkdir /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
|
||||
@@ -725,6 +727,26 @@ up_to_2.4.120() {
|
||||
INSTALLEDVERSION=2.4.120
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
@@ -219,6 +219,37 @@ http {
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
{% if 'api' in salt['pillar.get']('features', []) %}
|
||||
location ~* (^/oauth2/token.*|^.well-known/jwks.json|^.well-known/openid-configuration) {
|
||||
limit_req zone=auth_throttle burst={{ NGINXMERGED.config.throttle_login_burst }} nodelay;
|
||||
limit_req_status 429;
|
||||
proxy_pass http://{{ GLOBALS.manager }}:4444;
|
||||
proxy_read_timeout 90;
|
||||
proxy_connect_timeout 90;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Proxy "";
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location /connect/ {
|
||||
if ($http_authorization !~ "Bearer .*") {
|
||||
return 401;
|
||||
}
|
||||
rewrite /connect/(.*) /api/$1 break;
|
||||
proxy_pass http://{{ GLOBALS.manager }}:9822/;
|
||||
proxy_read_timeout 300;
|
||||
proxy_connect_timeout 300;
|
||||
proxy_set_header x-user-id "";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Proxy "";
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
{%- endif %}
|
||||
|
||||
location /cyberchef/ {
|
||||
auth_request /auth/sessions/whoami;
|
||||
proxy_read_timeout 90;
|
||||
@@ -329,6 +360,9 @@ http {
|
||||
error_page 429 = @error429;
|
||||
|
||||
location @error401 {
|
||||
if ($request_uri ~* (^/connect/.*|^/oauth2/.*)) {
|
||||
return 401;
|
||||
}
|
||||
if ($request_uri ~* ^/(?!(^/api/.*))) {
|
||||
add_header Set-Cookie "AUTH_REDIRECT=$request_uri;Path=/;Max-Age=14400";
|
||||
}
|
||||
@@ -336,6 +370,9 @@ http {
|
||||
}
|
||||
|
||||
location @error403 {
|
||||
if ($request_uri ~* (^/connect/.*|^/oauth2/.*)) {
|
||||
return 403;
|
||||
}
|
||||
add_header Set-Cookie "ory_kratos_session=;Path=/;Max-Age=0;expires=Thu, 01 Jan 1970 00:00:00 GMT;";
|
||||
return 302 /auth/self-service/login/browser;
|
||||
}
|
||||
|
||||
@@ -176,6 +176,12 @@ socusersroles:
|
||||
- require:
|
||||
- sls: manager.sync_es_users
|
||||
|
||||
socclientsroles:
|
||||
file.exists:
|
||||
- name: /opt/so/conf/soc/soc_clients_roles
|
||||
- require:
|
||||
- sls: manager.sync_es_users
|
||||
|
||||
socuploaddir:
|
||||
file.directory:
|
||||
- name: /nsm/soc/uploads
|
||||
|
||||
@@ -119,6 +119,13 @@ soc:
|
||||
- identity_id
|
||||
- http_request.headers.user-agent
|
||||
- msg
|
||||
':hydra:':
|
||||
- soc_timestamp
|
||||
- event.dataset
|
||||
- http_request.headers.x-real-ip
|
||||
- identity_id
|
||||
- http_request.headers.user-agent
|
||||
- msg
|
||||
'::conn':
|
||||
- soc_timestamp
|
||||
- event.dataset
|
||||
@@ -1311,6 +1318,8 @@ soc:
|
||||
jobDir: jobs
|
||||
kratos:
|
||||
hostUrl:
|
||||
hydra:
|
||||
hostUrl:
|
||||
elastalertengine:
|
||||
aiRepoUrl: https://github.com/Security-Onion-Solutions/securityonion-resources
|
||||
aiRepoBranch: generated-summaries-published
|
||||
@@ -1400,6 +1409,7 @@ soc:
|
||||
- rbac/custom_roles
|
||||
userFiles:
|
||||
- rbac/users_roles
|
||||
- rbac/clients_roles
|
||||
strelkaengine:
|
||||
aiRepoUrl: https://github.com/Security-Onion-Solutions/securityonion-resources
|
||||
aiRepoBranch: generated-summaries-published
|
||||
|
||||
@@ -44,6 +44,7 @@ so-soc:
|
||||
- /opt/so/conf/soc/custom.js:/opt/sensoroni/html/js/custom.js:ro
|
||||
- /opt/so/conf/soc/custom_roles:/opt/sensoroni/rbac/custom_roles:ro
|
||||
- /opt/so/conf/soc/soc_users_roles:/opt/sensoroni/rbac/users_roles:rw
|
||||
- /opt/so/conf/soc/soc_clients_roles:/opt/sensoroni/rbac/clients_roles:rw
|
||||
- /opt/so/conf/soc/queue:/opt/sensoroni/queue:rw
|
||||
- /opt/so/saltstack:/opt/so/saltstack:rw
|
||||
- /opt/so/conf/soc/migrations:/opt/so/conf/soc/migrations:rw
|
||||
@@ -82,6 +83,7 @@ so-soc:
|
||||
- file: soccustom
|
||||
- file: soccustomroles
|
||||
- file: socusersroles
|
||||
- file: socclientsroles
|
||||
|
||||
delete_so-soc_so-status.disabled:
|
||||
file.uncomment:
|
||||
|
||||
@@ -89,7 +89,7 @@ function manage_user() {
|
||||
add)
|
||||
email=$(echo "$request" | jq -r .email)
|
||||
password=$(echo "$request" | jq -r .password)
|
||||
role=$(echo "$request" | jq -r .role)
|
||||
perm=$(echo "$request" | jq -r .role)
|
||||
firstName=$(echo "$request" | jq -r .firstName)
|
||||
lastName=$(echo "$request" | jq -r .lastName)
|
||||
note=$(echo "$request" | jq -r .note)
|
||||
@@ -97,7 +97,7 @@ function manage_user() {
|
||||
response=$(echo "$password" | so-user "$op" --email "$email" --firstName "$firstName" --lastName "$lastName" --note "$note" --role "$role" --skip-sync)
|
||||
exit_code=$?
|
||||
;;
|
||||
add|enable|disable|delete)
|
||||
enable|disable|delete)
|
||||
email=$(echo "$request" | jq -r .email)
|
||||
log "Performing user '$op' for user '$email'"
|
||||
response=$(so-user "$op" --email "$email" --skip-sync)
|
||||
@@ -155,6 +155,77 @@ function manage_user() {
|
||||
fi
|
||||
}
|
||||
|
||||
function manage_client() {
|
||||
id=$1
|
||||
request=$2
|
||||
op=$(echo "$request" | jq -r .operation)
|
||||
|
||||
webResponse="true"
|
||||
max_tries=10
|
||||
tries=0
|
||||
while [[ $tries -lt $max_tries ]]; do
|
||||
case "$op" in
|
||||
add)
|
||||
name=$(echo "$request" | jq -r .name)
|
||||
note=$(echo "$request" | jq -r .note)
|
||||
log "Performing client '$op' for client with name '$name' and note '$note'"
|
||||
response=$(so-client "$op" --name "$name" --note "$note" --json)
|
||||
exit_code=$?
|
||||
webResponse=$response
|
||||
;;
|
||||
delete)
|
||||
client_id=$(echo "$request" | jq -r .id)
|
||||
log "Performing client '$op' for client '$client_id'"
|
||||
response=$(so-client "$op" --id "$client_id")
|
||||
exit_code=$?
|
||||
;;
|
||||
addperm|delperm)
|
||||
client_id=$(echo "$request" | jq -r .id)
|
||||
perm=$(echo "$request" | jq -r .permission)
|
||||
log "Performing '$op' for client '$client_id' with permission '$perm'"
|
||||
response=$(so-client "$op" --id "$client_id" --permission "$perm")
|
||||
exit_code=$?
|
||||
;;
|
||||
generate-secret)
|
||||
client_id=$(echo "$request" | jq -r .id)
|
||||
log "Performing '$op' operation for client '$client_id'"
|
||||
response=$(so-client "$op" --id "$client_id" --json)
|
||||
exit_code=$?
|
||||
webResponse=$response
|
||||
;;
|
||||
update)
|
||||
client_id=$(echo "$request" | jq -r .id)
|
||||
name=$(echo "$request" | jq -r .name)
|
||||
note=$(echo "$request" | jq -r .note)
|
||||
searchusername=$(echo "$request" | jq -r .searchusername)
|
||||
log "Performing '$op' update for client '$client_id' with name '$name', search username '$searchusername', and note '$note'"
|
||||
response=$(so-client "$op" --id "$client_id" --name "$name" --searchusername "$searchusername" --note "$note")
|
||||
exit_code=$?
|
||||
;;
|
||||
*)
|
||||
response="Unsupported client operation: $op"
|
||||
exit_code=1
|
||||
;;
|
||||
esac
|
||||
|
||||
tries=$((tries+1))
|
||||
if [[ "$response" == "Another process is using so-user"* ]]; then
|
||||
log "Retrying after brief delay to let so-user unlock ($tries/$max_tries)"
|
||||
sleep 5
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ exit_code -eq 0 ]]; then
|
||||
log "Successful command execution"
|
||||
respond "$id" "$webResponse"
|
||||
else
|
||||
log "Unsuccessful command execution: $response ($exit_code)"
|
||||
respond "$id" "false"
|
||||
fi
|
||||
}
|
||||
|
||||
function manage_salt() {
|
||||
id=$1
|
||||
request=$2
|
||||
@@ -319,6 +390,9 @@ while true; do
|
||||
list-minions)
|
||||
list_minions "$id"
|
||||
;;
|
||||
manage-client)
|
||||
manage_client "$id" "${request}"
|
||||
;;
|
||||
manage-minion)
|
||||
manage_minion "$id" "${request}"
|
||||
;;
|
||||
|
||||
@@ -62,6 +62,7 @@ base:
|
||||
- influxdb
|
||||
- soc
|
||||
- kratos
|
||||
- hydra
|
||||
- sensoroni
|
||||
- telegraf
|
||||
- firewall
|
||||
@@ -91,6 +92,7 @@ base:
|
||||
- strelka.manager
|
||||
- soc
|
||||
- kratos
|
||||
- hydra
|
||||
- firewall
|
||||
- manager
|
||||
- sensoroni
|
||||
@@ -123,6 +125,7 @@ base:
|
||||
- influxdb
|
||||
- soc
|
||||
- kratos
|
||||
- hydra
|
||||
- firewall
|
||||
- sensoroni
|
||||
- telegraf
|
||||
@@ -169,6 +172,7 @@ base:
|
||||
- strelka.manager
|
||||
- soc
|
||||
- kratos
|
||||
- hydra
|
||||
- firewall
|
||||
- manager
|
||||
- sensoroni
|
||||
@@ -220,6 +224,7 @@ base:
|
||||
- strelka.manager
|
||||
- soc
|
||||
- kratos
|
||||
- hydra
|
||||
- sensoroni
|
||||
- telegraf
|
||||
- firewall
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
{%
|
||||
do GLOBALS.update({
|
||||
'application_urls': {
|
||||
'hydra': 'http://' ~ GLOBALS.manager ~ ':4445/',
|
||||
'kratos': 'http://' ~ GLOBALS.manager ~ ':4434/',
|
||||
'elastic': 'https://' ~ GLOBALS.manager ~ ':9200/',
|
||||
'influxdb': 'https://' ~ GLOBALS.manager ~ ':8086/'
|
||||
|
||||
@@ -791,6 +791,7 @@ create_manager_pillars() {
|
||||
redis_pillar
|
||||
idstools_pillar
|
||||
kratos_pillar
|
||||
hydra_pillar
|
||||
soc_pillar
|
||||
idh_pillar
|
||||
influxdb_pillar
|
||||
@@ -1108,6 +1109,8 @@ generate_passwords(){
|
||||
INFLUXTOKEN=$(head -c 64 /dev/urandom | base64 --wrap=0)
|
||||
SENSORONIKEY=$(get_random_value)
|
||||
KRATOSKEY=$(get_random_value)
|
||||
HYDRAKEY=$(get_random_value)
|
||||
HYDRASALT=$(get_random_value)
|
||||
REDISPASS=$(get_random_value)
|
||||
SOCSRVKEY=$(get_random_value 64)
|
||||
IMPORTPASS=$(get_random_value)
|
||||
@@ -1303,6 +1306,24 @@ kratos_pillar() {
|
||||
"" > "$kratos_pillar_file"
|
||||
}
|
||||
|
||||
hydra_pillar() {
|
||||
title "Create the Hydra pillar file"
|
||||
touch $adv_hydra_pillar_file
|
||||
touch $hydra_pillar_file
|
||||
chmod 660 $hydra_pillar_file
|
||||
printf '%s\n'\
|
||||
"hydra:"\
|
||||
" config:"\
|
||||
" secrets:"\
|
||||
" system:"\
|
||||
" - '$HYDRAKEY'"\
|
||||
" oidc:"\
|
||||
" subject_identifiers:"\
|
||||
" pairwise:"\
|
||||
" salt: '$HYDRASALT'"\
|
||||
"" > "$hydra_pillar_file"
|
||||
}
|
||||
|
||||
create_global() {
|
||||
title "Creating the global.sls"
|
||||
touch $adv_global_pillar_file
|
||||
@@ -1404,10 +1425,10 @@ 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 idstools idh elastalert stig global kafka versionlock; 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
|
||||
for THEDIR in bpf pcap elasticsearch ntp firewall redis backup influxdb strelka sensoroni soc docker zeek suricata nginx telegraf logstash soc manager kratos hydra idstools idh elastalert stig global kafka versionlock; 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
|
||||
done
|
||||
}
|
||||
|
||||
@@ -1639,6 +1660,7 @@ reinstall_init() {
|
||||
# Backup (and erase) directories in /nsm to prevent app errors
|
||||
backup_dir /nsm/mysql "$date_string"
|
||||
backup_dir /nsm/kratos "$date_string"
|
||||
backup_dir /nsm/hydra "$date_string"
|
||||
backup_dir /nsm/influxdb "$date_string"
|
||||
|
||||
# Uninstall local Elastic Agent, if installed
|
||||
|
||||
@@ -160,6 +160,12 @@ export kratos_pillar_file
|
||||
adv_kratos_pillar_file="$local_salt_dir/pillar/kratos/adv_kratos.sls"
|
||||
export adv_kratos_pillar_file
|
||||
|
||||
hydra_pillar_file="$local_salt_dir/pillar/hydra/soc_hydra.sls"
|
||||
export hydra_pillar_file
|
||||
|
||||
adv_hydra_pillar_file="$local_salt_dir/pillar/hydra/adv_hydra.sls"
|
||||
export adv_hydra_pillar_file
|
||||
|
||||
idstools_pillar_file="$local_salt_dir/pillar/idstools/soc_idstools.sls"
|
||||
export idstools_pillar_file
|
||||
|
||||
|
||||
Reference in New Issue
Block a user