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" }