From 12168531a1eea8f50d1b4d4503969c4c2fb47815 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 16 Oct 2024 12:33:03 -0400 Subject: [PATCH 01/35] avoid double SSO clicks on initial OIDC login --- salt/kratos/defaults.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/kratos/defaults.yaml b/salt/kratos/defaults.yaml index b62e4d2ce..598a94fa1 100644 --- a/salt/kratos/defaults.yaml +++ b/salt/kratos/defaults.yaml @@ -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 From 15c32f9103c4bfbdd1b7b90b8dd55b8c1df955fc Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 16 Oct 2024 12:33:14 -0400 Subject: [PATCH 02/35] connect routes --- salt/nginx/etc/nginx.conf | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index 1e45f0db5..fc18e1fe8 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -219,6 +219,35 @@ http { proxy_set_header X-Forwarded-Proto $scheme; } + location /connect/token { + rewrite /connect/token(.*) /oauth2/token$1 break; + 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/api { + if ($http_authorization !~ "Bearer .*") { + return 403; + } + 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; + } + location /cyberchef/ { auth_request /auth/sessions/whoami; proxy_read_timeout 90; From 523ff66389400f6c4ec4dca0aefa8de933accc90 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 16 Oct 2024 13:44:01 -0400 Subject: [PATCH 03/35] connect work --- pillar/top.sls | 14 ++- salt/allowed_states.map.jinja | 5 + salt/backup/defaults.yaml | 1 + salt/common/tools/sbin/so-image-common | 2 + salt/docker/defaults.yaml | 8 ++ salt/docker/soc_docker.yaml | 1 + .../grid-nodes_general/hydra-logs.json | 30 +++++ salt/elasticsearch/defaults.yaml | 110 ++++++++++++++++++ salt/elasticsearch/files/ingest/hydra | 9 ++ salt/elasticsearch/soc_elasticsearch.yaml | 1 + salt/firewall/containers.map.jinja | 3 + salt/hydra/config.sls | 50 ++++++++ salt/hydra/defaults.yaml | 37 ++++++ salt/hydra/disabled.sls | 27 +++++ salt/hydra/enabled.sls | 105 +++++++++++++++++ salt/hydra/files/hydra.yaml.jinja | 1 + salt/hydra/init.sls | 13 +++ salt/hydra/map.jinja | 7 ++ salt/hydra/soc_hydra.yaml | 4 + salt/hydra/sostatus.sls | 21 ++++ salt/logrotate/defaults.yaml | 10 ++ salt/logrotate/soc_logrotate.yaml | 7 ++ salt/manager/tools/sbin/so-minion | 12 ++ salt/nginx/etc/nginx.conf | 2 + salt/soc/defaults.yaml | 7 ++ salt/top.sls | 5 + setup/so-functions | 23 +++- setup/so-variables | 6 + 28 files changed, 513 insertions(+), 8 deletions(-) create mode 100644 salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json create mode 100644 salt/elasticsearch/files/ingest/hydra create mode 100644 salt/hydra/config.sls create mode 100644 salt/hydra/defaults.yaml create mode 100644 salt/hydra/disabled.sls create mode 100644 salt/hydra/enabled.sls create mode 100644 salt/hydra/files/hydra.yaml.jinja create mode 100644 salt/hydra/init.sls create mode 100644 salt/hydra/map.jinja create mode 100644 salt/hydra/soc_hydra.yaml create mode 100644 salt/hydra/sostatus.sls diff --git a/pillar/top.sls b/pillar/top.sls index 131b39a99..0762f14a7 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -47,6 +47,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 @@ -96,6 +98,7 @@ base: - kibana.secrets {% endif %} - kratos.soc_kratos + - kratos.adv_kratos - elasticsearch.soc_elasticsearch - elasticsearch.adv_elasticsearch - elasticfleet.soc_elasticfleet @@ -113,8 +116,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 @@ -149,6 +152,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 @@ -262,6 +267,7 @@ base: - kibana.secrets {% endif %} - kratos.soc_kratos + - kratos.adv_kratos - elasticsearch.soc_elasticsearch - elasticsearch.adv_elasticsearch - elasticfleet.soc_elasticfleet @@ -277,8 +283,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 diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index a9a8b7c5e..a3d5c1354 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -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', diff --git a/salt/backup/defaults.yaml b/salt/backup/defaults.yaml index 1aae64910..dde128a80 100644 --- a/salt/backup/defaults.yaml +++ b/salt/backup/defaults.yaml @@ -4,4 +4,5 @@ backup: - /etc/pki - /etc/salt - /nsm/kratos + - /nsm/hydra destination: "/nsm/backup" \ No newline at end of file diff --git a/salt/common/tools/sbin/so-image-common b/salt/common/tools/sbin/so-image-common index c57749570..7fd35d5ac 100755 --- a/salt/common/tools/sbin/so-image-common +++ b/salt/common/tools/sbin/so-image-common @@ -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" diff --git a/salt/docker/defaults.yaml b/salt/docker/defaults.yaml index 161dde485..d6cb0de9c 100644 --- a/salt/docker/defaults.yaml +++ b/salt/docker/defaults.yaml @@ -51,6 +51,14 @@ docker: custom_bind_mounts: [] extra_hosts: [] extra_env: [] + 'so-hydra': + final_octet: 28 + port_bindings: + - 0.0.0.0:4444:4444 + - 0.0.0.0:4454:4445 + custom_bind_mounts: [] + extra_hosts: [] + extra_env: [] 'so-logstash': final_octet: 29 port_bindings: diff --git a/salt/docker/soc_docker.yaml b/salt/docker/soc_docker.yaml index e7ecba6be..dacbf2302 100644 --- a/salt/docker/soc_docker.yaml +++ b/salt/docker/soc_docker.yaml @@ -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 diff --git a/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json b/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json new file mode 100644 index 000000000..f1b1dace9 --- /dev/null +++ b/salt/elasticfleet/files/integrations/grid-nodes_general/hydra-logs.json @@ -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 +} diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 06f5392d8..823b33f22 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -794,6 +794,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: diff --git a/salt/elasticsearch/files/ingest/hydra b/salt/elasticsearch/files/ingest/hydra new file mode 100644 index 000000000..6bb2c22d8 --- /dev/null +++ b/salt/elasticsearch/files/ingest/hydra @@ -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" } } + ] +} \ No newline at end of file diff --git a/salt/elasticsearch/soc_elasticsearch.yaml b/salt/elasticsearch/soc_elasticsearch.yaml index 31a8a7f6f..7fd6d08b2 100644 --- a/salt/elasticsearch/soc_elasticsearch.yaml +++ b/salt/elasticsearch/soc_elasticsearch.yaml @@ -539,6 +539,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 diff --git a/salt/firewall/containers.map.jinja b/salt/firewall/containers.map.jinja index 02a1b7cac..cc0a20299 100644 --- a/salt/firewall/containers.map.jinja +++ b/salt/firewall/containers.map.jinja @@ -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' ] %} diff --git a/salt/hydra/config.sls b/salt/hydra/config.sls new file mode 100644 index 000000000..6f914aa5f --- /dev/null +++ b/salt/hydra/config.sls @@ -0,0 +1,50 @@ +# 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 + - defaults: + hydraMERGED: {{ hydraMERGED }} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/hydra/defaults.yaml b/salt/hydra/defaults.yaml new file mode 100644 index 000000000..99615cb00 --- /dev/null +++ b/salt/hydra/defaults.yaml @@ -0,0 +1,37 @@ +hydra: + enabled: False + config: + serve: + cookies: + same_site_mode: Lax + + public: + port: 4444 + admin: + port: 4445 + urls: + self: + issuer: https://URL_BASE/connect + public: https://URL_BASE/connect + admin: http://localhost:4445 + login: https://URL_BASE/login + logout: https://URL_BASE/logout + identity_provider: + url: http://127.0.0.1:4434/admin + publicUrl: https://URL_BASE/auth + headers: + Authorization: Bearer some-token + + secrets: + system: [] + + oidc: + subject_identifiers: + supported_types: + - pairwise + - public + pairwise: + salt: "" + + sqa: + opt_out: true \ No newline at end of file diff --git a/salt/hydra/disabled.sls b/salt/hydra/disabled.sls new file mode 100644 index 000000000..c940a5bd6 --- /dev/null +++ b/salt/hydra/disabled.sls @@ -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 %} diff --git a/salt/hydra/enabled.sls b/salt/hydra/enabled.sls new file mode 100644 index 000000000..3548afb4f --- /dev/null +++ b/salt/hydra/enabled.sls @@ -0,0 +1,105 @@ +# 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: hydraschema + - file: hydraconfig + - require: + - file: hydraschema + - 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 %} diff --git a/salt/hydra/files/hydra.yaml.jinja b/salt/hydra/files/hydra.yaml.jinja new file mode 100644 index 000000000..fe6a33546 --- /dev/null +++ b/salt/hydra/files/hydra.yaml.jinja @@ -0,0 +1 @@ +{{ HYDRAMERGED.config | yaml(false) }} diff --git a/salt/hydra/init.sls b/salt/hydra/init.sls new file mode 100644 index 000000000..eb7792bca --- /dev/null +++ b/salt/hydra/init.sls @@ -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 %} diff --git a/salt/hydra/map.jinja b/salt/hydra/map.jinja new file mode 100644 index 000000000..e6cd747a4 --- /dev/null +++ b/salt/hydra/map.jinja @@ -0,0 +1,7 @@ +{# 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 %} diff --git a/salt/hydra/soc_hydra.yaml b/salt/hydra/soc_hydra.yaml new file mode 100644 index 000000000..3f6c30442 --- /dev/null +++ b/salt/hydra/soc_hydra.yaml @@ -0,0 +1,4 @@ +hydra: + enabled: + description: Enables or disables the API authentication system, used for service account authentication. + helpLink: api.html diff --git a/salt/hydra/sostatus.sls b/salt/hydra/sostatus.sls new file mode 100644 index 000000000..8878bed4f --- /dev/null +++ b/salt/hydra/sostatus.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. + +{% 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 %} diff --git a/salt/logrotate/defaults.yaml b/salt/logrotate/defaults.yaml index 7333c78e9..2f7247ff2 100644 --- a/salt/logrotate/defaults.yaml +++ b/salt/logrotate/defaults.yaml @@ -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 diff --git a/salt/logrotate/soc_logrotate.yaml b/salt/logrotate/soc_logrotate.yaml index 62aa935c9..56f879e4f 100644 --- a/salt/logrotate/soc_logrotate.yaml +++ b/salt/logrotate/soc_logrotate.yaml @@ -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 diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index ebbfa8fff..c978803bb 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -368,6 +368,13 @@ function add_kratos_to_minion() { " " >> $PILLARFILE } +function add_hydra_to_minion() { + printf '%s\n'\ + "hydra:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + function add_idstools_to_minion() { printf '%s\n'\ "idstools:"\ @@ -448,6 +455,7 @@ function createEVAL() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion + add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -468,6 +476,7 @@ function createSTANDALONE() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion + add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -484,6 +493,7 @@ function createMANAGER() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion + add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -500,6 +510,7 @@ function createMANAGERSEARCH() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion + add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -514,6 +525,7 @@ function createIMPORT() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion + add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index fc18e1fe8..1521cc710 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -219,6 +219,7 @@ http { proxy_set_header X-Forwarded-Proto $scheme; } +{% if 'api' in salt['pillar.get']('features', []) %} location /connect/token { rewrite /connect/token(.*) /oauth2/token$1 break; limit_req zone=auth_throttle burst={{ NGINXMERGED.config.throttle_login_burst }} nodelay; @@ -247,6 +248,7 @@ http { proxy_set_header Proxy ""; proxy_set_header X-Forwarded-Proto $scheme; } +{%- endif %} location /cyberchef/ { auth_request /auth/sessions/whoami; diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 2d2a26c9a..7a8ee697f 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -119,6 +119,13 @@ soc: - identity_id - http_request.headers.user-agent - msg + ':kratos:': + - soc_timestamp + - event.dataset + - http_request.headers.x-real-ip + - identity_id + - http_request.headers.user-agent + - msg '::conn': - soc_timestamp - event.dataset diff --git a/salt/top.sls b/salt/top.sls index d876806f2..c4ad5d12f 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -61,6 +61,7 @@ base: - influxdb - soc - kratos + - hydra - sensoroni - telegraf - firewall @@ -90,6 +91,7 @@ base: - strelka.manager - soc - kratos + - hydra - firewall - manager - sensoroni @@ -122,6 +124,7 @@ base: - influxdb - soc - kratos + - hydra - firewall - sensoroni - telegraf @@ -168,6 +171,7 @@ base: - strelka.manager - soc - kratos + - hydra - firewall - manager - sensoroni @@ -219,6 +223,7 @@ base: - strelka.manager - soc - kratos + - hydra - sensoroni - telegraf - firewall diff --git a/setup/so-functions b/setup/so-functions index 5ebf76c17..5e36851c2 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -791,6 +791,7 @@ create_manager_pillars() { redis_pillar idstools_pillar kratos_pillar + hydra_pillar soc_pillar idh_pillar influxdb_pillar @@ -1108,6 +1109,7 @@ generate_passwords(){ INFLUXTOKEN=$(head -c 64 /dev/urandom | base64 --wrap=0) SENSORONIKEY=$(get_random_value) KRATOSKEY=$(get_random_value) + HYDRAKEY=$(get_random_value) REDISPASS=$(get_random_value) SOCSRVKEY=$(get_random_value 64) IMPORTPASS=$(get_random_value) @@ -1303,6 +1305,18 @@ kratos_pillar() { "" > "$kratos_pillar_file" } +hydra_pillar() { + title "Create the Hydra pillar file" + touch $adv_hydra_pillar_file + printf '%s\n'\ + "hydra:"\ + " config:"\ + " secrets:"\ + " system:"\ + " - '$HYDRAKEY'"\ + "" > "$hydra_pillar_file" +} + create_global() { title "Creating the global.sls" touch $adv_global_pillar_file @@ -1404,10 +1418,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;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;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 +1653,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 diff --git a/setup/so-variables b/setup/so-variables index ecc29b554..fc253df0a 100644 --- a/setup/so-variables +++ b/setup/so-variables @@ -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 From 1e5bf3aa987b84c4e45728d8c8eaf1f89f52d5b7 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 16 Oct 2024 14:21:11 -0400 Subject: [PATCH 04/35] connect upgrade --- salt/manager/tools/sbin/soup | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index c592dffe4..2cd108d00 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -404,6 +404,7 @@ preupgrade_changes() { [[ "$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.120 true } @@ -425,6 +426,7 @@ postupgrade_changes() { [[ "$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.120 true } @@ -517,6 +519,11 @@ post_to_2.4.110() { POSTVERSION=2.4.110 } +post_to_2.4.120() { + echo "Nothing to apply" + POSTVERSION=2.4.120 +} + repo_sync() { echo "Sync the local repo." su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync." @@ -705,6 +712,29 @@ up_to_2.4.110() { INSTALLEDVERSION=2.4.110 } +up_to_2.4.120() { + echo "Nothing to do for 2.4.120" + + add_hydra_pillars + + 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) + printf '%s\n'\ + "hydra:"\ + " config:"\ + " secrets:"\ + " system:"\ + " - '$HYDRAKEY'"\ + "" > /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" From d8546bf74786f35c014f989c2c30e4bb34853f73 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 16 Oct 2024 14:59:15 -0400 Subject: [PATCH 05/35] connect upgrade --- salt/hydra/map.jinja | 2 ++ 1 file changed, 2 insertions(+) diff --git a/salt/hydra/map.jinja b/salt/hydra/map.jinja index e6cd747a4..fdc5d2e9d 100644 --- a/salt/hydra/map.jinja +++ b/salt/hydra/map.jinja @@ -5,3 +5,5 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} {% import_yaml 'hydra/defaults.yaml' as HYDRADEFAULTS %} + +{% set HYDRAMERGED = salt['pillar.get']('hydra', default=HYDRADEFAULTS.hydra, merge=true) %} \ No newline at end of file From f713dbacf87912bc26452742357489b297c8ed9a Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 16 Oct 2024 17:53:57 -0400 Subject: [PATCH 06/35] connect --- salt/soc/defaults.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 3fe1bf123..52ca5fe8c 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -119,7 +119,7 @@ soc: - identity_id - http_request.headers.user-agent - msg - ':kratos:': + ':hydra:': - soc_timestamp - event.dataset - http_request.headers.x-real-ip From 435b9b14e3e72127bcdce56445c0c2b737aa1003 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 17 Oct 2024 10:49:39 -0400 Subject: [PATCH 07/35] connect wip --- salt/hydra/soc_hydra.yaml | 2 +- salt/manager/tools/sbin/so-minion | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/salt/hydra/soc_hydra.yaml b/salt/hydra/soc_hydra.yaml index 3f6c30442..1b6523c22 100644 --- a/salt/hydra/soc_hydra.yaml +++ b/salt/hydra/soc_hydra.yaml @@ -1,4 +1,4 @@ hydra: enabled: - description: Enables or disables the API authentication system, used for service account authentication. + 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: api.html diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index c978803bb..ebbfa8fff 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -368,13 +368,6 @@ function add_kratos_to_minion() { " " >> $PILLARFILE } -function add_hydra_to_minion() { - printf '%s\n'\ - "hydra:"\ - " enabled: True"\ - " " >> $PILLARFILE -} - function add_idstools_to_minion() { printf '%s\n'\ "idstools:"\ @@ -455,7 +448,6 @@ function createEVAL() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion - add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -476,7 +468,6 @@ function createSTANDALONE() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion - add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -493,7 +484,6 @@ function createMANAGER() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion - add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -510,7 +500,6 @@ function createMANAGERSEARCH() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion - add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } @@ -525,7 +514,6 @@ function createIMPORT() { add_soc_to_minion add_registry_to_minion add_kratos_to_minion - add_hydra_to_minion add_idstools_to_minion add_elastic_fleet_package_registry_to_minion } From 25fe83cd4053f79585beb8feda2924ebf26a3405 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 17 Oct 2024 11:22:10 -0400 Subject: [PATCH 08/35] connect wip --- salt/hydra/config.sls | 5 +++-- salt/hydra/enabled.sls | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/salt/hydra/config.sls b/salt/hydra/config.sls index 6f914aa5f..f74726cc1 100644 --- a/salt/hydra/config.sls +++ b/salt/hydra/config.sls @@ -5,7 +5,7 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls.split('.')[0] in allowed_states %} -{% from "hydra/map.jinja" import hydraMERGED %} +{% from "hydra/map.jinja" import HYDRAMERGED %} hydradir: file.directory: @@ -38,8 +38,9 @@ hydraconfig: - group: 928 - mode: 600 - template: jinja + - makedirs: True - defaults: - hydraMERGED: {{ hydraMERGED }} + HYDRAMERGED: {{ HYDRAMERGED }} {% else %} diff --git a/salt/hydra/enabled.sls b/salt/hydra/enabled.sls index 3548afb4f..e0f03e184 100644 --- a/salt/hydra/enabled.sls +++ b/salt/hydra/enabled.sls @@ -54,10 +54,8 @@ so-hydra: {% endif %} - restart_policy: unless-stopped - watch: - - file: hydraschema - file: hydraconfig - require: - - file: hydraschema - file: hydraconfig - file: hydralogdir - file: hydradir From 1537b69457b1ad8c2909ff16ae06c9d806ad28c0 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 17 Oct 2024 11:25:40 -0400 Subject: [PATCH 09/35] connect wip --- salt/docker/defaults.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/docker/defaults.yaml b/salt/docker/defaults.yaml index d6cb0de9c..9a33611c2 100644 --- a/salt/docker/defaults.yaml +++ b/salt/docker/defaults.yaml @@ -52,7 +52,7 @@ docker: extra_hosts: [] extra_env: [] 'so-hydra': - final_octet: 28 + final_octet: 30 port_bindings: - 0.0.0.0:4444:4444 - 0.0.0.0:4454:4445 From 4611ef371308415ba95f0646f8e80e429a2bd9a0 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 17 Oct 2024 11:39:36 -0400 Subject: [PATCH 10/35] connect wip --- salt/hydra/defaults.yaml | 13 ++++--------- salt/hydra/map.jinja | 7 +++++++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/salt/hydra/defaults.yaml b/salt/hydra/defaults.yaml index 99615cb00..a9a26c151 100644 --- a/salt/hydra/defaults.yaml +++ b/salt/hydra/defaults.yaml @@ -2,13 +2,10 @@ hydra: enabled: False config: serve: - cookies: - same_site_mode: Lax - - public: - port: 4444 - admin: - port: 4445 + public: + port: 4444 + admin: + port: 4445 urls: self: issuer: https://URL_BASE/connect @@ -19,8 +16,6 @@ hydra: identity_provider: url: http://127.0.0.1:4434/admin publicUrl: https://URL_BASE/auth - headers: - Authorization: Bearer some-token secrets: system: [] diff --git a/salt/hydra/map.jinja b/salt/hydra/map.jinja index fdc5d2e9d..ca801a700 100644 --- a/salt/hydra/map.jinja +++ b/salt/hydra/map.jinja @@ -6,4 +6,11 @@ {% 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)}) %} +{% do HYDRADEFAULTS.hydra.config.urls.update({'login': HYDRADEFAULTS.hydra.config.urls.login | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do HYDRADEFAULTS.hydra.config.urls.update({'logout': HYDRADEFAULTS.hydra.config.urls.logout | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do HYDRADEFAULTS.hydra.config.urls.identity_provider.update({'publicUrl': HYDRADEFAULTS.hydra.config.urls.identity_provider.publicUrl | replace("URL_BASE", GLOBALS.url_base)}) %} + {% set HYDRAMERGED = salt['pillar.get']('hydra', default=HYDRADEFAULTS.hydra, merge=true) %} \ No newline at end of file From 5e6dd2e8b324f487870ed25e26c0b9227528992a Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 23 Oct 2024 16:49:02 -0400 Subject: [PATCH 11/35] connect --- salt/docker/defaults.yaml | 2 +- salt/hydra/defaults.yaml | 4 +- salt/manager/sync_es_users.sls | 1 + salt/manager/tools/sbin/so-user | 16 +++++++ salt/manager/tools/sbin/soup | 5 ++ salt/soc/defaults.yaml | 2 + salt/soc/enabled.sls | 1 + salt/soc/files/bin/salt-relay.sh | 78 +++++++++++++++++++++++++++++++- salt/vars/globals.map.jinja | 1 + setup/so-functions | 7 +++ 10 files changed, 114 insertions(+), 3 deletions(-) diff --git a/salt/docker/defaults.yaml b/salt/docker/defaults.yaml index 9a33611c2..21cdf606c 100644 --- a/salt/docker/defaults.yaml +++ b/salt/docker/defaults.yaml @@ -55,7 +55,7 @@ docker: final_octet: 30 port_bindings: - 0.0.0.0:4444:4444 - - 0.0.0.0:4454:4445 + - 0.0.0.0:4445:4445 custom_bind_mounts: [] extra_hosts: [] extra_env: [] diff --git a/salt/hydra/defaults.yaml b/salt/hydra/defaults.yaml index a9a26c151..af032da04 100644 --- a/salt/hydra/defaults.yaml +++ b/salt/hydra/defaults.yaml @@ -27,6 +27,8 @@ hydra: - public pairwise: salt: "" - + log: + level: debug + format: json sqa: opt_out: true \ No newline at end of file diff --git a/salt/manager/sync_es_users.sls b/salt/manager/sync_es_users.sls index 03645c699..829eeed14 100644 --- a/salt/manager/sync_es_users.sls +++ b/salt/manager/sync_es_users.sls @@ -16,6 +16,7 @@ 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_client_roles - show_changes: False - require: - docker_container: so-kratos diff --git a/salt/manager/tools/sbin/so-user b/salt/manager/tools/sbin/so-user index e4b2b7464..845e1585e 100755 --- a/salt/manager/tools/sbin/so-user +++ b/salt/manager/tools/sbin/so-user @@ -136,6 +136,7 @@ bcryptRounds=${BCRYPT_ROUNDS:-12} elasticUsersFile=${ELASTIC_USERS_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users} elasticRolesFile=${ELASTIC_ROLES_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users_roles} socRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_users_roles} +clientRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_client_roles} esUID=${ELASTIC_UID:-930} esGID=${ELASTIC_GID:-930} soUID=${SOCORE_UID:-939} @@ -282,6 +283,18 @@ function ensureRoleFileExists() { fi mv "${rolesTmpFile}" "${socRolesFile}" fi + + if [[ ! -f "$clientRolesFile" || ! -s "$clientRolesFile" ]]; then + # Generate the new client roles file + rolesTmpFile="${clientRolesFile}.tmp" + createFile "$rolesTmpFile" "$soUID" "$soGID" + + if [[ -d "$clientRolesFile" ]]; then + echo "Removing invalid roles directory created by Docker" + rm -fr "$clientRolesFile" + fi + mv "${rolesTmpFile}" "${clientRolesFile}" + fi } function syncElasticSystemUser() { @@ -374,6 +387,9 @@ function syncElastic() { [[ $? != 0 ]] && fail "Unable to read role identities from database" done < "$socRolesFile" + # Append the client roles + cat "$clientRolesFile" >> "$rolesTmpFile" + else echo "Database file or soc roles file does not exist yet, skipping users export" fi diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 2cd108d00..fe5883294 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -726,12 +726,17 @@ add_hydra_pillars() { 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 } diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 52ca5fe8c..f39a72f89 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1318,6 +1318,8 @@ soc: jobDir: jobs kratos: hostUrl: + hydra: + hostUrl: elastalertengine: aiRepoUrl: https://github.com/Security-Onion-Solutions/securityonion-resources aiRepoBranch: generated-summaries-published diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls index 99499115c..ac89a9763 100644 --- a/salt/soc/enabled.sls +++ b/salt/soc/enabled.sls @@ -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_client_roles:/opt/sensoroni/rbac/client_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 diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 4b183b20a..d36e8549e 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -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,82 @@ 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) + role=$(echo "$request" | jq -r .role) + name=$(echo "$request" | jq -r .name) + note=$(echo "$request" | jq -r .note) + log "Performing client '$op' for client with name '$name', note '$note' and role '$role'" + response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --skip-sync) + webResponse=$resposne + exit_code=$? + ;; + delete) + id=$(echo "$request" | jq -r .id) + log "Performing client '$op' for client '$id'" + response=$(so-client "$op" --id "$id" --skip-sync) + exit_code=$? + ;; + addrole|delrole) + id=$(echo "$request" | jq -r .id) + role=$(echo "$request" | jq -r .role) + log "Performing '$op' for client '$id' with role '$role'" + response=$(so-client "$op" --id "$id" --role "$role" --skip-sync) + exit_code=$? + ;; + generate-secret) + id=$(echo "$request" | jq -r .id) + log "Performing '$op' operation for client '$id'" + response=$(so-client "$op" --id "$id" --skip-sync) + webResponse=$response + exit_code=$? + ;; + update) + id=$(echo "$request" | jq -r .id) + name=$(echo "$request" | jq -r .name) + note=$(echo "$request" | jq -r .note) + log "Performing '$op' update for client '$id' with name '$name', and note '$note'" + response=$(so-client "$op" --id "$id" --name "$name" --note "$note") + exit_code=$? + ;; + sync) + log "Performing '$op'" + response=$(so-user "$op") + 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 diff --git a/salt/vars/globals.map.jinja b/salt/vars/globals.map.jinja index 0a4995c0c..000cfa354 100644 --- a/salt/vars/globals.map.jinja +++ b/salt/vars/globals.map.jinja @@ -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/' diff --git a/setup/so-functions b/setup/so-functions index 5e36851c2..be57776f7 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1110,6 +1110,7 @@ generate_passwords(){ 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) @@ -1308,12 +1309,18 @@ kratos_pillar() { 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" } From 7c405ff9d73b47ff91a2497b928772d8c1f94821 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 24 Oct 2024 08:47:52 -0400 Subject: [PATCH 12/35] connect --- salt/manager/sync_es_users.sls | 3 ++- salt/manager/tools/sbin/so-user | 2 +- salt/soc/config.sls | 6 ++++++ salt/soc/defaults.yaml | 1 + salt/soc/enabled.sls | 3 ++- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/salt/manager/sync_es_users.sls b/salt/manager/sync_es_users.sls index 829eeed14..3aebef993 100644 --- a/salt/manager/sync_es_users.sls +++ b/salt/manager/sync_es_users.sls @@ -16,12 +16,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_client_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 diff --git a/salt/manager/tools/sbin/so-user b/salt/manager/tools/sbin/so-user index 845e1585e..03855f661 100755 --- a/salt/manager/tools/sbin/so-user +++ b/salt/manager/tools/sbin/so-user @@ -136,7 +136,7 @@ bcryptRounds=${BCRYPT_ROUNDS:-12} elasticUsersFile=${ELASTIC_USERS_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users} elasticRolesFile=${ELASTIC_ROLES_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users_roles} socRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_users_roles} -clientRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_client_roles} +clientRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_clients_roles} esUID=${ELASTIC_UID:-930} esGID=${ELASTIC_GID:-930} soUID=${SOCORE_UID:-939} diff --git a/salt/soc/config.sls b/salt/soc/config.sls index 7607da5ff..5174dd94e 100644 --- a/salt/soc/config.sls +++ b/salt/soc/config.sls @@ -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 diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index f39a72f89..ae5f83edd 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1403,6 +1403,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 diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls index ac89a9763..d1582721d 100644 --- a/salt/soc/enabled.sls +++ b/salt/soc/enabled.sls @@ -44,7 +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_client_roles:/opt/sensoroni/rbac/client_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 @@ -83,6 +83,7 @@ so-soc: - file: soccustom - file: soccustomroles - file: socusersroles + - file: socclientroles delete_so-soc_so-status.disabled: file.uncomment: From cacd5b06435b573e918cedffb96508a6f7580abd Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 24 Oct 2024 09:36:09 -0400 Subject: [PATCH 13/35] connect --- salt/manager/sync_es_users.sls | 4 + salt/manager/tools/sbin/so-client | 331 ++++++++++++++++++++++++++++++ salt/soc/enabled.sls | 2 +- 3 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 salt/manager/tools/sbin/so-client diff --git a/salt/manager/sync_es_users.sls b/salt/manager/sync_es_users.sls index 3aebef993..c46b58ce2 100644 --- a/salt/manager/sync_es_users.sls +++ b/salt/manager/sync_es_users.sls @@ -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: diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client new file mode 100644 index 000000000..04e540465 --- /dev/null +++ b/salt/manager/tools/sbin/so-client @@ -0,0 +1,331 @@ +#!/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 + + +DEFAULT_ROLE=limited-auditor + +function usage() { + cat < [supporting parameters] + + where is one of the following: + + list: Lists all client IDs and roles currently defined in the oauth2 system + + add: Adds a new client to the oauth2 system and outputs the generated secret + Required parameters: + --name + Optional parameters: + --role (defaults to $DEFAULT_ROLE) + --note (defaults to blank) + + delete: Deletes a client from the oauth2 system + Required parameters: + --id + + addrole: Grants a role to an existing client + Required parameters: + --id + --role + + delrole: Removes a role from an existing client + Required parameters: + --id + --role + + generate-secret: Regenerates a client's secret and outputs the new secret. + Required parameters: + --id + Optional parameters: + --skip-sync (defers the Elastic sync until the next scheduled time) + +USAGE_EOF + exit 1 +} + +if [[ $# -lt 1 || $1 == --help || $1 == -h || $1 == -? || $1 == --h ]]; then + usage +fi + +operation=$1 +shift + +while [[ $# -gt 0 ]]; do + param=$1 + shift + case "$param" in + --id) + id=$1 + shift + ;; + --role) + role=$1 + shift + ;; + --name) + name=$1 + shift + ;; + --note) + note=$1 + shift + ;; + *) + echo "Encountered unexpected parameter: $param" + usage + ;; + esac +done + +hydraUrl=${HYDRA_URL:-http://127.0.0.1:4445/admin} +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" != "404 page not found" ]] && 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 ${hydraUrl}/admin/clients) + [[ $? != 0 ]] && fail "Unable to communicate with Hydra" + + clientIds=$(echo "${response}" | jq -r ".[] | .client_id" | sort) + for clientId in $clientIds; do + roles=$(grep ":$clientId\$" "$socRolesFile" | cut -d: -f1 | tr '\n' ' ') + echo "$clientId: $roles" + done +} + +function addClientRole() { + id=$1 + role=$2 + + adjustClientRole "$id" "$role" "add" +} + +function deleteClientRole() { + id=$1 + role=$2 + + adjustClientRole "$id" "$role" "del" +} + +function adjustClientRole() { + identityId=$1 + role=$2 + op=$3 + + [[ ${identityId} == "" ]] && fail "Client not found" + + ensureRoleFileExists + + filename="$socRolesFile" + hasRole=0 + grep "^$role:" "$socRolesFile" | grep -q "$identityId" && hasRole=1 + if [[ "$op" == "add" ]]; then + if [[ "$hasRole" == "1" ]]; then + echo "Client '$identityId' already has the role: $role" + return 1 + else + echo "$role:$identityId" >> "$filename" + fi + elif [[ "$op" == "del" ]]; then + if [[ "$hasRole" -ne 1 ]]; then + fail "Client '$identityId' does not have the role: $role" + else + sed "/^$role:$identityId\$/d" "$filename" > "$filename.tmp" + cat "$filename".tmp > "$filename" + rm -f "$filename".tmp + fi + else + fail "Unsupported role adjustment operation: $op" + fi + return 0 +} + +function convertNameToId() { + name=$1 + + name=${name//[^[:alnum:]]/_} + echo "$name" | tr '[:upper:]' '[:lower:]' +} + +function createClient() { + name=$1 + role=$2 + note=$3 + + id=$(convertNameToId "$name") + now=$(date -u +%FT%TZ) + body=$(cat < "$rolesTmpFile" + cat "$rolesTmpFile" > "$socRolesFile" +} + +case "${operation}" in + "add") + verifyEnvironment + [[ "$name" == "" ]] && fail "A short client name must be provided" + + lock + createClient "$name" "${role:-$DEFAULT_ROLE}" "${note}" + echo "Successfully added new client to SOC. Run 'so-user sync' to sync with Elasticsearch." + ;; + + "list") + verifyEnvironment + listClients + ;; + + "addrole") + verifyEnvironment + [[ "$id" == "" ]] && fail "Id must be provided" + [[ "$role" == "" ]] && fail "Role must be provided" + + lock + if addClientRole "$email" "$role"; then + echo "Successfully added role to client" + fi + ;; + + "delrole") + verifyEnvironment + [[ "$id" == "" ]] && fail "Id must be provided" + [[ "$role" == "" ]] && fail "Role must be provided" + + lock + deleteClientRole "$email" "$role" + echo "Successfully removed role from client" + ;; + + "generate-secret") + verifyEnvironment + [[ "$id" == "" ]] && fail "Id must be provided" + + lock + generateSecret "$id" + echo "Successfully generated secret" + ;; + + "delete") + verifyEnvironment + [[ "$id" == "" ]] && fail "Id must be provided" + + lock + deleteClient "$email" + echo "Successfully deleted client. Run 'so-user sync' to sync with Elasticsearch." + ;; + *) + fail "Unsupported operation: $operation" + usage + ;; +esac + +exit 0 diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls index d1582721d..32437bd99 100644 --- a/salt/soc/enabled.sls +++ b/salt/soc/enabled.sls @@ -83,7 +83,7 @@ so-soc: - file: soccustom - file: soccustomroles - file: socusersroles - - file: socclientroles + - file: socclientsroles delete_so-soc_so-status.disabled: file.uncomment: From d9273ec369773d3a1d722ffd355932a938d52aa0 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 24 Oct 2024 09:40:47 -0400 Subject: [PATCH 14/35] exec bit --- salt/manager/tools/sbin/so-client | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 salt/manager/tools/sbin/so-client diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client old mode 100644 new mode 100755 From d503c09ef2791fa9f2b0ed9aa7aa876ec8560428 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 24 Oct 2024 15:45:18 -0400 Subject: [PATCH 15/35] connect --- salt/manager/tools/sbin/so-client | 54 ++++++++++++++++++------------- salt/nginx/etc/nginx.conf | 6 ++-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 04e540465..4177e84b0 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -87,7 +87,7 @@ while [[ $# -gt 0 ]]; do esac done -hydraUrl=${HYDRA_URL:-http://127.0.0.1:4445/admin} +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} @@ -116,7 +116,7 @@ function verifyEnvironment() { require "jq" require "curl" response=$(curl -Ss -L ${hydraUrl}/) - [[ "$response" != "404 page not found" ]] && fail "Unable to communicate with Hydra; specify URL via HYDRA_URL environment variable" + [[ "$response" != *"Error 404"* ]] && fail "Unable to communicate with Hydra; specify URL via HYDRA_URL environment variable" } function createFile() { @@ -145,7 +145,7 @@ function ensureRoleFileExists() { } function listClients() { - response=$(curl -Ss -L ${hydraUrl}/admin/clients) + response=$(curl -Ss -L -f ${hydraUrl}/admin/clients) [[ $? != 0 ]] && fail "Unable to communicate with Hydra" clientIds=$(echo "${response}" | jq -r ".[] | .client_id" | sort) @@ -192,7 +192,7 @@ function adjustClientRole() { if [[ "$hasRole" -ne 1 ]]; then fail "Client '$identityId' does not have the role: $role" else - sed "/^$role:$identityId\$/d" "$filename" > "$filename.tmp" + sed -e "\!^$role:$identityId\$!d" "$filename" > "$filename.tmp" cat "$filename".tmp > "$filename" rm -f "$filename".tmp fi @@ -206,7 +206,7 @@ function convertNameToId() { name=$1 name=${name//[^[:alnum:]]/_} - echo "$name" | tr '[:upper:]' '[:lower:]' + echo "socl_$name" | tr '[:upper:]' '[:lower:]' } function createClient() { @@ -216,11 +216,15 @@ function createClient() { id=$(convertNameToId "$name") now=$(date -u +%FT%TZ) + secret=$(get_random_value) body=$(cat < Date: Mon, 28 Oct 2024 19:11:26 -0400 Subject: [PATCH 16/35] connect --- salt/manager/tools/sbin/so-client | 47 +++++++++++++++++++++++++++++++ salt/soc/files/bin/salt-relay.sh | 6 ++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 4177e84b0..944214dd5 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -42,6 +42,12 @@ function usage() { Required parameters: --id --role + + update: Updates a client name and note. + Required parameters: + --id + --name + --note generate-secret: Regenerates a client's secret and outputs the new secret. Required parameters: @@ -240,6 +246,36 @@ EOF addClientRole "$id" "$role" } +function update() { + clientId=$1 + name=$2 + note=$3 + + body=$(cat < Date: Mon, 28 Oct 2024 19:25:20 -0400 Subject: [PATCH 17/35] connect --- salt/soc/files/bin/salt-relay.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index e803a613f..6a6164d31 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -395,6 +395,9 @@ while true; do list-minions) list_minions "$id" ;; + manage-client) + manage_client "$id" "${request}" + ;; manage-minion) manage_minion "$id" "${request}" ;; From 1243c7588b8d8bc7d0574811bda34240ed78db75 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Mon, 28 Oct 2024 19:42:01 -0400 Subject: [PATCH 18/35] connect --- salt/soc/files/bin/salt-relay.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 6a6164d31..8186e7941 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -175,31 +175,31 @@ function manage_client() { exit_code=$? ;; delete) - id=$(echo "$request" | jq -r .id) - log "Performing client '$op' for client '$id'" - response=$(so-client "$op" --id "$id") + client_id=$(echo "$request" | jq -r .id) + log "Performing client '$op' for client '$client_id'" + response=$(so-client "$op" --id "$client_id") exit_code=$? ;; addrole|delrole) - id=$(echo "$request" | jq -r .id) + client_id=$(echo "$request" | jq -r .id) role=$(echo "$request" | jq -r .role) - log "Performing '$op' for client '$id' with role '$role'" - response=$(so-client "$op" --id "$id" --role "$role") + log "Performing '$op' for client '$client_id' with role '$role'" + response=$(so-client "$op" --id "$client_id" --role "$role") exit_code=$? ;; generate-secret) - id=$(echo "$request" | jq -r .id) - log "Performing '$op' operation for client '$id'" - response=$(so-client "$op" --id "$id") + client_id=$(echo "$request" | jq -r .id) + log "Performing '$op' operation for client '$client_id'" + response=$(so-client "$op" --id "$client_id") webResponse=$response exit_code=$? ;; update) - id=$(echo "$request" | jq -r .id) + client_id=$(echo "$request" | jq -r .id) name=$(echo "$request" | jq -r .name) note=$(echo "$request" | jq -r .note) - log "Performing '$op' update for client '$id' with name '$name', and note '$note'" - response=$(so-client "$op" --id "$id" --name "$name" --note "$note") + log "Performing '$op' update for client '$client_id' with name '$name', and note '$note'" + response=$(so-client "$op" --id "$client_id" --name "$name" --note "$note") exit_code=$? ;; sync) From 11820a16f0919845d254530129fa90ee32bf9082 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Tue, 29 Oct 2024 12:04:38 -0400 Subject: [PATCH 19/35] connect --- salt/manager/tools/sbin/so-client | 18 +++++++++++++++--- salt/soc/files/bin/salt-relay.sh | 4 ++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 944214dd5..c1d352328 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -28,6 +28,7 @@ function usage() { Optional parameters: --role (defaults to $DEFAULT_ROLE) --note (defaults to blank) + --raw only output generated secret delete: Deletes a client from the oauth2 system Required parameters: @@ -53,7 +54,7 @@ function usage() { Required parameters: --id Optional parameters: - --skip-sync (defers the Elastic sync until the next scheduled time) + --raw only output generated secret USAGE_EOF exit 1 @@ -86,6 +87,9 @@ while [[ $# -gt 0 ]]; do note=$1 shift ;; + --raw) + raw=1 + ;; *) echo "Encountered unexpected parameter: $param" usage @@ -322,7 +326,11 @@ case "${operation}" in lock createClient "$name" "${role:-$DEFAULT_ROLE}" "${note}" - echo "Successfully added user and generated secret: $secret" + if [[ "$raw" == "1" ]]; then + echo $secret + else + echo "Successfully added user and generated secret: $secret" + fi ;; "list") @@ -368,7 +376,11 @@ case "${operation}" in lock generateSecret "$id" - echo "Successfully generated secret: $secret" + if [[ "$raw" == "1" ]]; then + echo $secret + else + echo "Successfully generated secret: $secret" + fi ;; "delete") diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 8186e7941..241e33663 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -170,7 +170,7 @@ function manage_client() { name=$(echo "$request" | jq -r .name) note=$(echo "$request" | jq -r .note) log "Performing client '$op' for client with name '$name', note '$note' and role '$role'" - response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --skip-sync) + response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --raw) webResponse=$resposne exit_code=$? ;; @@ -190,7 +190,7 @@ function manage_client() { generate-secret) client_id=$(echo "$request" | jq -r .id) log "Performing '$op' operation for client '$client_id'" - response=$(so-client "$op" --id "$client_id") + response=$(so-client "$op" --id "$client_id" --raw) webResponse=$response exit_code=$? ;; From 3f3ac21f509e8b2dab72fd61f38eb4cde2c1e5e5 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Tue, 29 Oct 2024 12:28:24 -0400 Subject: [PATCH 20/35] connect --- salt/soc/files/bin/salt-relay.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 241e33663..bc8ac169f 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -171,7 +171,7 @@ function manage_client() { note=$(echo "$request" | jq -r .note) log "Performing client '$op' for client with name '$name', note '$note' and role '$role'" response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --raw) - webResponse=$resposne + webResponse=$response exit_code=$? ;; delete) From a146153ee920c77f3dfc3c0e76da176d0a4a50a9 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Wed, 30 Oct 2024 12:44:01 -0400 Subject: [PATCH 21/35] switch to json --- salt/manager/tools/sbin/so-client | 18 +++++++++--------- salt/soc/files/bin/salt-relay.sh | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index c1d352328..5b8365f86 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -28,7 +28,7 @@ function usage() { Optional parameters: --role (defaults to $DEFAULT_ROLE) --note (defaults to blank) - --raw only output generated secret + --json output as JSON delete: Deletes a client from the oauth2 system Required parameters: @@ -54,7 +54,7 @@ function usage() { Required parameters: --id Optional parameters: - --raw only output generated secret + --json output as JSON USAGE_EOF exit 1 @@ -87,8 +87,8 @@ while [[ $# -gt 0 ]]; do note=$1 shift ;; - --raw) - raw=1 + --json) + json=1 ;; *) echo "Encountered unexpected parameter: $param" @@ -326,10 +326,10 @@ case "${operation}" in lock createClient "$name" "${role:-$DEFAULT_ROLE}" "${note}" - if [[ "$raw" == "1" ]]; then - echo $secret + if [[ "$json" == "1" ]]; then + echo "{\"id\":\"$id\",\"secret\":\"$secret\"}" else - echo "Successfully added user and generated secret: $secret" + echo "Successfully added user ID $id with generated secret: $secret" fi ;; @@ -376,8 +376,8 @@ case "${operation}" in lock generateSecret "$id" - if [[ "$raw" == "1" ]]; then - echo $secret + if [[ "$json" == "1" ]]; then + echo "{\"secret\":\"$secret\"}" else echo "Successfully generated secret: $secret" fi diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index bc8ac169f..8bd40384c 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -170,7 +170,7 @@ function manage_client() { name=$(echo "$request" | jq -r .name) note=$(echo "$request" | jq -r .note) log "Performing client '$op' for client with name '$name', note '$note' and role '$role'" - response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --raw) + response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --json) webResponse=$response exit_code=$? ;; @@ -190,7 +190,7 @@ function manage_client() { generate-secret) client_id=$(echo "$request" | jq -r .id) log "Performing '$op' operation for client '$client_id'" - response=$(so-client "$op" --id "$client_id" --raw) + response=$(so-client "$op" --id "$client_id" --json) webResponse=$response exit_code=$? ;; From 370b1179384ecdfe45b8e7bd10c233ae3f755efe Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 31 Oct 2024 16:39:45 -0400 Subject: [PATCH 22/35] rename role --- salt/manager/tools/sbin/so-client | 82 +++++++++++++++---------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 5b8365f86..482dc021c 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -11,22 +11,18 @@ else source $(dirname $0)/../../../common/tools/sbin/so-common fi - -DEFAULT_ROLE=limited-auditor - function usage() { cat < [supporting parameters] where is one of the following: - list: Lists all client IDs and roles currently defined in the oauth2 system + 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 Optional parameters: - --role (defaults to $DEFAULT_ROLE) --note (defaults to blank) --json output as JSON @@ -34,15 +30,15 @@ function usage() { Required parameters: --id - addrole: Grants a role to an existing client + addperm: Grants a permission to an existing client Required parameters: --id - --role + --permission - delrole: Removes a role from an existing client + delperm: Removes a permission from an existing client Required parameters: --id - --role + --permission update: Updates a client name and note. Required parameters: @@ -73,18 +69,22 @@ while [[ $# -gt 0 ]]; do case "$param" in --id) id=$1 + [[ ${#id} -gt 55 ]] && fail("id cannot be longer than 55 characters") shift ;; - --role) - role=$1 + --permission) + perm=$1 + [[ ${#perm} -gt 50 ]] && fail("permission cannot be longer than 50 characters") shift ;; --name) name=$1 + [[ ${#name} -gt 50 ]] && fail("name cannot be longer than 50 characters") shift ;; --note) note=$1 + [[ ${#note} -gt 50 ]] && fail("note cannot be longer than 500 characters") shift ;; --json) @@ -160,28 +160,28 @@ function listClients() { clientIds=$(echo "${response}" | jq -r ".[] | .client_id" | sort) for clientId in $clientIds; do - roles=$(grep ":$clientId\$" "$socRolesFile" | cut -d: -f1 | tr '\n' ' ') - echo "$clientId: $roles" + perms=$(grep ":$clientId\$" "$socRolesFile" | cut -d: -f1 | tr '\n' ' ') + echo "$clientId: $perms" done } -function addClientRole() { +function addClientPermission() { id=$1 - role=$2 + perm=$2 - adjustClientRole "$id" "$role" "add" + adjustClientPermission "$id" "$perm" "add" } -function deleteClientRole() { +function deleteClientPermission() { id=$1 - role=$2 + perm=$2 - adjustClientRole "$id" "$role" "del" + adjustClientPermission "$id" "$perm" "del" } -function adjustClientRole() { +function adjustClientPermission() { identityId=$1 - role=$2 + perm=$2 op=$3 [[ ${identityId} == "" ]] && fail "Client not found" @@ -189,25 +189,25 @@ function adjustClientRole() { ensureRoleFileExists filename="$socRolesFile" - hasRole=0 - grep "^$role:" "$socRolesFile" | grep -q "$identityId" && hasRole=1 + hasPerm=0 + grep "^$perm:" "$socRolesFile" | grep -q "$identityId" && hasPerm=1 if [[ "$op" == "add" ]]; then - if [[ "$hasRole" == "1" ]]; then - echo "Client '$identityId' already has the role: $role" + if [[ "$hasPerm" == "1" ]]; then + echo "Client '$identityId' already has the permission: $perm" return 1 else - echo "$role:$identityId" >> "$filename" + echo "$perm:$identityId" >> "$filename" fi elif [[ "$op" == "del" ]]; then - if [[ "$hasRole" -ne 1 ]]; then - fail "Client '$identityId' does not have the role: $role" + if [[ "$hasPermission" -ne 1 ]]; then + fail "Client '$identityId' does not have the permission: $perm" else - sed -e "\!^$role:$identityId\$!d" "$filename" > "$filename.tmp" + sed -e "\!^$perm:$identityId\$!d" "$filename" > "$filename.tmp" cat "$filename".tmp > "$filename" rm -f "$filename".tmp fi else - fail "Unsupported role adjustment operation: $op" + fail "Unsupported permission adjustment operation: $op" fi return 0 } @@ -221,7 +221,7 @@ function convertNameToId() { function createClient() { name=$1 - role=$2 + perm=$2 note=$3 id=$(convertNameToId "$name") @@ -247,7 +247,7 @@ EOF error=$(echo $response | jq .error) fail "Failed to submit request to Hydra: $error" fi - addClientRole "$id" "$role" + addClientPermission "$id" "$perm" } function update() { @@ -325,7 +325,7 @@ case "${operation}" in [[ "$name" == "" ]] && fail "A short client name must be provided" lock - createClient "$name" "${role:-$DEFAULT_ROLE}" "${note}" + createClient "$name" "${note}" if [[ "$json" == "1" ]]; then echo "{\"id\":\"$id\",\"secret\":\"$secret\"}" else @@ -338,25 +338,25 @@ case "${operation}" in listClients ;; - "addrole") + "addperm") verifyEnvironment [[ "$id" == "" ]] && fail "Id must be provided" - [[ "$role" == "" ]] && fail "Role must be provided" + [[ "$perm" == "" ]] && fail "Permission must be provided" lock - if addClientRole "$id" "$role"; then - echo "Successfully added role to client" + if addClientPermission "$id" "$perm"; then + echo "Successfully added permission to client" fi ;; - "delrole") + "delperm") verifyEnvironment [[ "$id" == "" ]] && fail "Id must be provided" - [[ "$role" == "" ]] && fail "Role must be provided" + [[ "$perm" == "" ]] && fail "Permission must be provided" lock - deleteClientRole "$id" "$role" - echo "Successfully removed role from client" + deleteClientPermission "$id" "$perm" + echo "Successfully removed permission from client" ;; "update") From 520c9d8d51ab08b380ee317ef2bd8e24c81c9608 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 31 Oct 2024 16:42:42 -0400 Subject: [PATCH 23/35] rename role --- salt/manager/tools/sbin/so-client | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 482dc021c..3f6d9f6f4 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -69,22 +69,22 @@ while [[ $# -gt 0 ]]; do case "$param" in --id) id=$1 - [[ ${#id} -gt 55 ]] && fail("id cannot be longer than 55 characters") + [[ ${#id} -gt 55 ]] && fail "id cannot be longer than 55 characters" shift ;; --permission) perm=$1 - [[ ${#perm} -gt 50 ]] && fail("permission cannot be longer than 50 characters") + [[ ${#perm} -gt 50 ]] && fail "permission cannot be longer than 50 characters" shift ;; --name) name=$1 - [[ ${#name} -gt 50 ]] && fail("name cannot be longer than 50 characters") + [[ ${#name} -gt 50 ]] && fail "name cannot be longer than 50 characters" shift ;; --note) note=$1 - [[ ${#note} -gt 50 ]] && fail("note cannot be longer than 500 characters") + [[ ${#note} -gt 50 ]] && fail "note cannot be longer than 500 characters" shift ;; --json) From cd2e5bf2d0835702c8d95ef2f79f6f8c76ef90f8 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 31 Oct 2024 17:20:44 -0400 Subject: [PATCH 24/35] rename role --- salt/manager/tools/sbin/so-client | 1 - salt/soc/files/bin/salt-relay.sh | 15 +++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 3f6d9f6f4..d9191bd59 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -247,7 +247,6 @@ EOF error=$(echo $response | jq .error) fail "Failed to submit request to Hydra: $error" fi - addClientPermission "$id" "$perm" } function update() { diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 8bd40384c..42955a3e8 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -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) @@ -166,11 +166,10 @@ function manage_client() { while [[ $tries -lt $max_tries ]]; do case "$op" in add) - role=$(echo "$request" | jq -r .role) name=$(echo "$request" | jq -r .name) note=$(echo "$request" | jq -r .note) - log "Performing client '$op' for client with name '$name', note '$note' and role '$role'" - response=$(so-client "$op" --name "$name" --note "$note" --role "$role" --json) + log "Performing client '$op' for client with name '$name' and note '$note'" + response=$(so-client "$op" --name "$name" --note "$note" --json) webResponse=$response exit_code=$? ;; @@ -180,11 +179,11 @@ function manage_client() { response=$(so-client "$op" --id "$client_id") exit_code=$? ;; - addrole|delrole) + addperm|delperm) client_id=$(echo "$request" | jq -r .id) - role=$(echo "$request" | jq -r .role) - log "Performing '$op' for client '$client_id' with role '$role'" - response=$(so-client "$op" --id "$client_id" --role "$role") + 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) From 825dbb36ddfe350e5d35c1866b61c91652f799e2 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 1 Nov 2024 15:37:59 -0400 Subject: [PATCH 25/35] connect --- salt/manager/tools/sbin/so-client | 17 ++++++++++++----- salt/manager/tools/sbin/so-user | 18 ------------------ salt/soc/files/bin/salt-relay.sh | 10 +++------- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index d9191bd59..87c0d8daa 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -45,6 +45,7 @@ function usage() { --id --name --note + --searchusername generate-secret: Regenerates a client's secret and outputs the new secret. Required parameters: @@ -84,7 +85,12 @@ while [[ $# -gt 0 ]]; do ;; --note) note=$1 - [[ ${#note} -gt 50 ]] && fail "note cannot be longer than 500 characters" + [[ ${#note} -gt 100 ]] && fail "note cannot be longer than 100 characters" + shift + ;; + --searchusername) + searchusername=$1 + [[ ${#searchusername} -gt 50 ]] && fail "search username cannot be longer than 50 characters" shift ;; --json) @@ -199,7 +205,7 @@ function adjustClientPermission() { echo "$perm:$identityId" >> "$filename" fi elif [[ "$op" == "del" ]]; then - if [[ "$hasPermission" -ne 1 ]]; then + if [[ "$hasPerm" -ne 1 ]]; then fail "Client '$identityId' does not have the permission: $perm" else sed -e "\!^$perm:$identityId\$!d" "$filename" > "$filename.tmp" @@ -328,7 +334,7 @@ case "${operation}" in if [[ "$json" == "1" ]]; then echo "{\"id\":\"$id\",\"secret\":\"$secret\"}" else - echo "Successfully added user ID $id with generated secret: $secret" + echo "Successfully added client ID $id with generated secret: $secret" fi ;; @@ -363,9 +369,10 @@ case "${operation}" in [[ "$id" == "" ]] && fail "Id must be provided" [[ "$name" == "" ]] && fail "Name must be provided" [[ "$note" == "" ]] && fail "Note must be provided" + [[ "$searchusername" == "" ]] && fail "Search Username must be provided" lock - update "$id" "$name" "$note" + update "$id" "$name" "$note" "$searchusername" echo "Successfully updated client" ;; @@ -388,7 +395,7 @@ case "${operation}" in lock deleteClient "$id" - echo "Successfully deleted client. Run 'so-user sync' to sync with Elasticsearch." + echo "Successfully deleted client." ;; *) fail "Unsupported operation: $operation" diff --git a/salt/manager/tools/sbin/so-user b/salt/manager/tools/sbin/so-user index 03855f661..e64bd1a8a 100755 --- a/salt/manager/tools/sbin/so-user +++ b/salt/manager/tools/sbin/so-user @@ -136,7 +136,6 @@ bcryptRounds=${BCRYPT_ROUNDS:-12} elasticUsersFile=${ELASTIC_USERS_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users} elasticRolesFile=${ELASTIC_ROLES_FILE:-/opt/so/saltstack/local/salt/elasticsearch/files/users_roles} socRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_users_roles} -clientRolesFile=${SOC_ROLES_FILE:-/opt/so/conf/soc/soc_clients_roles} esUID=${ELASTIC_UID:-930} esGID=${ELASTIC_GID:-930} soUID=${SOCORE_UID:-939} @@ -283,18 +282,6 @@ function ensureRoleFileExists() { fi mv "${rolesTmpFile}" "${socRolesFile}" fi - - if [[ ! -f "$clientRolesFile" || ! -s "$clientRolesFile" ]]; then - # Generate the new client roles file - rolesTmpFile="${clientRolesFile}.tmp" - createFile "$rolesTmpFile" "$soUID" "$soGID" - - if [[ -d "$clientRolesFile" ]]; then - echo "Removing invalid roles directory created by Docker" - rm -fr "$clientRolesFile" - fi - mv "${rolesTmpFile}" "${clientRolesFile}" - fi } function syncElasticSystemUser() { @@ -370,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 @@ -386,10 +372,6 @@ function syncElastic() { sqlite3 -cmd ".timeout ${databaseTimeout}" "$databasePath" >> "$rolesTmpFile" [[ $? != 0 ]] && fail "Unable to read role identities from database" done < "$socRolesFile" - - # Append the client roles - cat "$clientRolesFile" >> "$rolesTmpFile" - else echo "Database file or soc roles file does not exist yet, skipping users export" fi diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 42955a3e8..0ffdf9ad2 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -197,13 +197,9 @@ function manage_client() { client_id=$(echo "$request" | jq -r .id) name=$(echo "$request" | jq -r .name) note=$(echo "$request" | jq -r .note) - log "Performing '$op' update for client '$client_id' with name '$name', and note '$note'" - response=$(so-client "$op" --id "$client_id" --name "$name" --note "$note") - exit_code=$? - ;; - sync) - log "Performing '$op'" - response=$(so-user "$op") + 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=$? ;; *) From fb73517fc154f78e1c5a7f4eacd7139e42f37e6e Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 1 Nov 2024 15:43:26 -0400 Subject: [PATCH 26/35] connect --- salt/manager/tools/sbin/so-client | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 87c0d8daa..fdfb736e0 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -272,6 +272,7 @@ function update() { "path": "/metadata", "value": { "note": "$note" + "searchUsername": "$searchusername" } } ] From 755cfb4e13c45091103b0140f9c73473476ab442 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 1 Nov 2024 15:47:33 -0400 Subject: [PATCH 27/35] connect --- salt/manager/tools/sbin/so-client | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index fdfb736e0..524de58e8 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -243,6 +243,7 @@ function createClient() { "response_types": [ "code" ], "metadata": { "note": "$note" + "searchUsername": "" } } EOF @@ -271,7 +272,7 @@ function update() { "op": "replace", "path": "/metadata", "value": { - "note": "$note" + "note": "$note", "searchUsername": "$searchusername" } } From c9f6b5206a68f6488252ab1b50e7f684def6bbcd Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 1 Nov 2024 16:18:40 -0400 Subject: [PATCH 28/35] connect --- salt/manager/tools/sbin/so-client | 2 +- salt/soc/files/bin/salt-relay.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 524de58e8..1eeaf7392 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -242,7 +242,7 @@ function createClient() { "grant_types": [ "client_credentials" ], "response_types": [ "code" ], "metadata": { - "note": "$note" + "note": "$note", "searchUsername": "" } } diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index 0ffdf9ad2..18ce8c0b0 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -170,8 +170,8 @@ function manage_client() { 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) - webResponse=$response exit_code=$? + webResponse=$response ;; delete) client_id=$(echo "$request" | jq -r .id) @@ -190,8 +190,8 @@ function manage_client() { client_id=$(echo "$request" | jq -r .id) log "Performing '$op' operation for client '$client_id'" response=$(so-client "$op" --id "$client_id" --json) - webResponse=$response exit_code=$? + webResponse=$response ;; update) client_id=$(echo "$request" | jq -r .id) From 25479ca71fdb02d9424af295e797eb5beecaa0b8 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 1 Nov 2024 16:29:04 -0400 Subject: [PATCH 29/35] connect --- salt/manager/tools/sbin/so-client | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 1eeaf7392..261b8cc06 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -64,6 +64,9 @@ fi operation=$1 shift +searchUsername=__MISSING__ +note=__MISSING__ + while [[ $# -gt 0 ]]; do param=$1 shift @@ -89,8 +92,8 @@ while [[ $# -gt 0 ]]; do shift ;; --searchusername) - searchusername=$1 - [[ ${#searchusername} -gt 50 ]] && fail "search username cannot be longer than 50 characters" + searchUsername=$1 + [[ ${#searchUsername} -gt 50 ]] && fail "search username cannot be longer than 50 characters" shift ;; --json) @@ -260,6 +263,7 @@ function update() { clientId=$1 name=$2 note=$3 + username=$4 body=$(cat < Date: Fri, 1 Nov 2024 16:37:24 -0400 Subject: [PATCH 30/35] connect --- salt/manager/tools/sbin/so-client | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 261b8cc06..1b67ca4dc 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -375,10 +375,10 @@ case "${operation}" in [[ "$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" + [[ "$searchUsername" == "__MISSING__" ]] && fail "Search Username must be provided" lock - update "$id" "$name" "$note" "$searchusername" + update "$id" "$name" "$note" "$searchUsername" echo "Successfully updated client" ;; From e8ab7bce0c0b85e7ba29f221e7ceed8a8838d019 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Mon, 4 Nov 2024 10:49:30 -0500 Subject: [PATCH 31/35] connect --- salt/manager/tools/sbin/so-client | 15 +++++++-------- salt/manager/tools/sbin/so-user | 10 +++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/salt/manager/tools/sbin/so-client b/salt/manager/tools/sbin/so-client index 1b67ca4dc..e55ef70b5 100755 --- a/salt/manager/tools/sbin/so-client +++ b/salt/manager/tools/sbin/so-client @@ -72,27 +72,27 @@ while [[ $# -gt 0 ]]; do shift case "$param" in --id) - id=$1 + id=$(echo $1 | sed 's/"/\\"/g') [[ ${#id} -gt 55 ]] && fail "id cannot be longer than 55 characters" shift ;; --permission) - perm=$1 + perm=$(echo $1 | sed 's/"/\\"/g') [[ ${#perm} -gt 50 ]] && fail "permission cannot be longer than 50 characters" shift ;; --name) - name=$1 + name=$(echo $1 | sed 's/"/\\"/g') [[ ${#name} -gt 50 ]] && fail "name cannot be longer than 50 characters" shift ;; --note) - note=$1 + note=$(echo $1 | sed 's/"/\\"/g') [[ ${#note} -gt 100 ]] && fail "note cannot be longer than 100 characters" shift ;; --searchusername) - searchUsername=$1 + searchUsername=$(echo $1 | sed 's/"/\\"/g') [[ ${#searchUsername} -gt 50 ]] && fail "search username cannot be longer than 50 characters" shift ;; @@ -230,8 +230,7 @@ function convertNameToId() { function createClient() { name=$1 - perm=$2 - note=$3 + note=$2 id=$(convertNameToId "$name") now=$(date -u +%FT%TZ) @@ -336,7 +335,7 @@ case "${operation}" in [[ "$name" == "" ]] && fail "A short client name must be provided" lock - createClient "$name" "${note}" + createClient "$name" "$note" if [[ "$json" == "1" ]]; then echo "{\"id\":\"$id\",\"secret\":\"$secret\"}" else diff --git a/salt/manager/tools/sbin/so-user b/salt/manager/tools/sbin/so-user index e64bd1a8a..f34681c04 100755 --- a/salt/manager/tools/sbin/so-user +++ b/salt/manager/tools/sbin/so-user @@ -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) From ba0abb156a6949574af8a7f1cbfd839b908f3ad2 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 7 Nov 2024 16:08:28 -0500 Subject: [PATCH 32/35] connect --- salt/hydra/soc_hydra.yaml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/salt/hydra/soc_hydra.yaml b/salt/hydra/soc_hydra.yaml index 1b6523c22..1e33f00ea 100644 --- a/salt/hydra/soc_hydra.yaml +++ b/salt/hydra/soc_hydra.yaml @@ -1,4 +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: api.html + 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 From 97f4cbdade381ee07a9acd3aed413ec0a1f45e16 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 7 Nov 2024 16:16:37 -0500 Subject: [PATCH 33/35] connect --- salt/hydra/defaults.yaml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/salt/hydra/defaults.yaml b/salt/hydra/defaults.yaml index af032da04..cbea72b97 100644 --- a/salt/hydra/defaults.yaml +++ b/salt/hydra/defaults.yaml @@ -11,15 +11,11 @@ hydra: issuer: https://URL_BASE/connect public: https://URL_BASE/connect admin: http://localhost:4445 - login: https://URL_BASE/login - logout: https://URL_BASE/logout - identity_provider: - url: http://127.0.0.1:4434/admin - publicUrl: https://URL_BASE/auth - + secrets: system: [] - + ttl: + access_token: 1h oidc: subject_identifiers: supported_types: From 31cf6a2ebc55397df2c0987f5c3db5d6dac1c018 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Thu, 7 Nov 2024 16:17:30 -0500 Subject: [PATCH 34/35] connect --- salt/hydra/map.jinja | 3 --- 1 file changed, 3 deletions(-) diff --git a/salt/hydra/map.jinja b/salt/hydra/map.jinja index ca801a700..81e92073e 100644 --- a/salt/hydra/map.jinja +++ b/salt/hydra/map.jinja @@ -9,8 +9,5 @@ {% 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)}) %} -{% do HYDRADEFAULTS.hydra.config.urls.update({'login': HYDRADEFAULTS.hydra.config.urls.login | replace("URL_BASE", GLOBALS.url_base)}) %} -{% do HYDRADEFAULTS.hydra.config.urls.update({'logout': HYDRADEFAULTS.hydra.config.urls.logout | replace("URL_BASE", GLOBALS.url_base)}) %} -{% do HYDRADEFAULTS.hydra.config.urls.identity_provider.update({'publicUrl': HYDRADEFAULTS.hydra.config.urls.identity_provider.publicUrl | replace("URL_BASE", GLOBALS.url_base)}) %} {% set HYDRAMERGED = salt['pillar.get']('hydra', default=HYDRADEFAULTS.hydra, merge=true) %} \ No newline at end of file From d4ed34d0ea7041b0bd87a1a16261fc470022b5d1 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Mon, 11 Nov 2024 11:56:19 -0500 Subject: [PATCH 35/35] connect --- salt/nginx/etc/nginx.conf | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index 9eda44e73..09c40624e 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -235,7 +235,7 @@ http { location /connect/ { if ($http_authorization !~ "Bearer .*") { - return 403; + return 401; } rewrite /connect/(.*) /api/$1 break; proxy_pass http://{{ GLOBALS.manager }}:9822/; @@ -360,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"; } @@ -367,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; }