#!/bin/bash # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. . /usr/sbin/so-common usage() { echo "Usage: $0 [args]" echo "" echo "Supported Operations:" echo " dashboardpath Returns the URL path for a dashboard, requires: " echo " export Exports all templates to stdout" echo " setup Loads all templates and creates all required buckets" echo " userlist Lists users" echo " useradd Adds a new user, requires: " echo " userdel Removes an existing user, requires: " echo " userenable Enables a user, requires: " echo " userdisable Disables a user, requires: " echo " userpass Updates a user's password, requires: " echo " userpromote Promotes a user to admin: " echo " userdemote Demotes a user from admin: " echo "" echo "If required, the password will be read from STDIN." exit 1 } if [ $# -lt 1 ]; then usage fi COMMAND=$(basename $0) OP=$1 shift set -eo pipefail log() { echo -e "$(date) | $COMMAND | $@" >&2 } check_response() { response=$1 if [[ "$response" =~ "\"code\":" ]]; then log "Failed. Check the response for more details.\n$response" exit 1 fi } request() { curl -skK /opt/so/conf/influxdb/curl.config "https://localhost:8086/api/v2/$@" } lookup_user_id() { email=$1 response=$(request users?limit=100) check_response "$response" uid=$(echo "$response" | jq -r ".users[] | select(.name == \"$email\").id") if [[ -z "$uid" ]]; then log "User not found" exit 1 fi echo "$uid" } lookup_stack_id() { oid=$1 response=$(request "stacks?orgID=$oid&name=Security+Onion") check_response "$response" stackid=$(echo "$response" | jq -r ".stacks[0].id") if [[ -z "$stackid" || "$stackid" == null ]]; then response=$(request stacks -X POST -d "{\"name\":\"Security Onion\",\"orgID\":\"$oid\"}") check_response "$response" stackid=$(echo "$response" | jq -r .id) fi echo "$stackid" } change_password() { uid=$1 set +e test -t 0 if [[ $? == 0 ]]; then echo "Enter new password:" fi set -e read -rs pass check_password_and_exit "$pass" response=$(request users/$uid/password -X POST -d "{\"password\":\"$pass\"}") check_response "$response" } apply_templates() { oid=$1 stackid=$2 template_objects_array=$3 body="{\"orgID\":\"$oid\",\"stackID\":\"$stackid\",\"templates\":$template_objects_array}" response=$(request templates/apply -X POST -d "$body") check_response "$response" } setup_bucket() { oid=$1 name=$2 age=$3 shardduration=$4 response=$(request "buckets?orgID=$oid&name=$name") bucketid=$(echo "$response" | jq -r ".buckets[0].id") if [[ -z "$bucketid" || "$bucketid" == null ]]; then response=$(request buckets -X POST -d "{\"name\":\"$name\",\"orgID\":\"$oid\"}") check_response "$response" bucketid=$(echo "$response" | jq -r .id) fi response=$(request buckets/$bucketid -X PATCH -d "{\"name\":\"$name\",\"retentionRules\":[{\"everySeconds\":$age,\"shardGroupDurationSeconds\":$shardduration,\"type\":\"expire\"}]}") check_response "$response" } lookup_org_id_with_wait() { max_attempts=30 attempts=0 wait=10 while [[ $attempts -lt $max_attempts ]]; do response=$(request orgs?org=Security+Onion) oid=$(echo "$response" | jq -r ".orgs[] | select(.name == \"Security Onion\").id") if [[ -z $oid ]]; then attempts=$((attempts+1)) log "Server does not appear to be running or fully initialized - will try again in $wait seconds ($attempts / $max_attempts)" sleep $wait else echo "$oid" return fi done log "Server has not started after $max_attempts attempts - aborting" exit 1 } oid=$(lookup_org_id_with_wait) case "$OP" in setup) log "Ensuring organization is setup correctly" # Load templates if at least one has been modified since the last setup newest=$(ls -1t /opt/so/conf/influxdb/templates/ | head -1) if [ /opt/so/conf/influxdb/templates/$newest -nt /opt/so/conf/influxdb/last_template_setup ]; then log "Updating templates" stackid=$(lookup_stack_id "$oid") for file in /opt/so/conf/influxdb/templates/*; do if [[ "$templates_array" != "" ]]; then templates_array="$templates_array," fi template=$(cat "$file") templates_array="$templates_array{\"contents\":$template}" done apply_templates "$oid" "$stackid" "[$templates_array]" echo $(date) > /opt/so/conf/influxdb/last_template_setup else log "Templates have not been modified since last setup" fi # Setup buckets and retention periods if at least one has been modified since the last setup if [ /opt/so/conf/influxdb/buckets.json -nt /opt/so/conf/influxdb/last_bucket_setup ]; then log "Updating buckets and retention periods" for rp in so_short_term so_long_term; do bucket=telegraf/$rp log "Ensuring bucket is created and configured; bucket=$bucket" age=$(cat /opt/so/conf/influxdb/buckets.json | jq -r .$rp.duration) shard_duration=$(cat /opt/so/conf/influxdb/buckets.json | jq -r .$rp.shard_duration) setup_bucket "$oid" "$bucket" "$age" "$shard_duration" done echo $(date) > /opt/so/conf/influxdb/last_bucket_setup else log "Buckets have not been modified since last setup" fi ;; userlist) log "Listing existing users" response=$(request users) check_response "$response" echo "$response" | jq -r '.users[] | "\(.id): \(.name) (\(.status))"' ;; useradd) [ $# -ne 1 ] && usage email=$1 log "Adding new user; email=$email" response=$(request users -X POST -d "{\"name\":\"$email\"}") check_response "$response" uid=$(echo "$response" | jq -r .id) log "Adding new user to organization" response=$(request orgs/$oid/members -X POST -d "{\"id\":\"$uid\"}") check_response "$response" change_password "$uid" ;; userpass) [ $# -ne 1 ] && usage email=$1 log "Updating user password; email=$email" uid=$(lookup_user_id "$email") change_password "$uid" ;; userdel) [ $# -ne 1 ] && usage email=$1 log "Deleting user; email=$email" uid=$(lookup_user_id "$email") response=$(request users/$uid -X DELETE) check_response "$response" ;; userenable) [ $# -ne 1 ] && usage email=$1 log "Enabling user; email=$email" uid=$(lookup_user_id "$email") response=$(request users/$uid -X PATCH -d "{\"name\":\"$email\",\"status\":\"active\"}") check_response "$response" ;; userdisable) [ $# -ne 1 ] && usage email=$1 log "Disabling user; email=$email" uid=$(lookup_user_id "$email") response=$(request users/$uid -X PATCH -d "{\"name\":\"$email\",\"status\":\"inactive\"}") check_response "$response" ;; userpromote) [ $# -ne 1 ] && usage email=$1 log "Promoting user to admin; email=$email" uid=$(lookup_user_id "$email") response=$(request orgs/$oid/members/$uid -X DELETE) response=$(request orgs/$oid/owners -X POST -d "{\"id\":\"$uid\"}") check_response "$response" ;; userdemote) [ $# -ne 1 ] && usage email=$1 log "Demoting user from admin; email=$email" uid=$(lookup_user_id "$email") response=$(request orgs/$oid/owners/$uid -X DELETE) response=$(request orgs/$oid/members -X POST -d "{\"id\":\"$uid\"}") check_response "$response" ;; export) log "Exporting all organization templates" request templates/export -X POST -d "{\"orgIDs\":[{\"orgID\":\"$oid\"}]}" -H "Content-Type: application/json" ;; dashboardpath) [ $# -ne 1 ] && usage name=$1 response=$(request dashboards?limit=100&orgID=$oid) check_response "$response" dbid=$(echo "$response" | jq -r ".dashboards[] | select(.name == \"$name\").id") if [[ -z "$dbid" ]]; then log "Dashboard not found" exit 1 fi echo -n "/influxdb/orgs/$oid/dashboards/$dbid" ;; *) usage ;; esac