Splunk Dev

How to create a bulletin message to display to users in Splunk Web from a Python modular or scripted input?

hirsts
Path Finder

Does anyone know the best way to create bulletin messages to be presented to the user in the UI from a python modular or scripted input ?

I've found the "curl" based solutions to write directly to the REST endpoint however this is not a platform agnostic solution and calling an external method could expose the admin password.

Any ideas would be appreciated.

woodcock
Esteemed Legend

All-around amazing guy @jkat54 solved this with the `motd` command in his tools app here:
https://splunkbase.splunk.com/app/3265/#/details

jkat54
SplunkTrust
SplunkTrust

What about this approach?

import requests 
import cherrypy

def createMessage(sessionkey, title="Default Title",message="Default Message", severity="warn"):
 uri = "https://localhost:8089/services/messages/new"
 headers = {'Authorization':''}
 headers['Authorization'] = 'Splunk ' + sessionkey
 data ={'name':title,'value':message,'severity':severity}
 r = requests.post(uri, headers=headers, data=data, verify=False)
 if r.status_code<300:
  return True
 else:
  return r.status_code

sessionkey= cherrypy.session['sessionKey']
createMessage(sessionkey, title="AWESOME Title",message="AWESEOME Message", severity="warn")

jkat54
SplunkTrust
SplunkTrust

I think the above answers your question... you need to take that session key, and append it to a header called authorization, and then make the value equal 'Spunk ' + sessionKey, then use requests.post to post the request with the header and data, and if ssl is bad, verify = False.

Here's what my session key looks like when the above works:
'xXZNyBITUTA9nQDGv0OrBZSuc4mRF3pHtFlt80ie9FSB_m7uAsA6W0V1uXchpuuvoe_BGEUG0ILiz_6bAekoyl4DGlKs9KZTE^F'

jkat54
SplunkTrust
SplunkTrust

I've tried this within a custom search command called motd linked to motd.py and for the life of me I cant get it to work. The script executes fine even when I use the session key from cherrypy or splunk.intersplunk. However, nothing ever shows up... then i swap over to a script like the above where user/pass is "hardcoded" and it works just fine. I'm using 6.3.2 and python

Here's where i left the code last:

import cherrypy
import requests
import splunk.Intersplunk as si
import splunk.mining.dcutils as dcu

logger = dcu.getLogger()

help = """------------------------------------------------------------------------------------
motd title message severity
------------------------------------------------------------------------------------"""

contexthelp = """------------------------------------------------------------------------------------
motd creates a bulletin message
------------------------------------------------------------------------------------"""

def motd(title="default title",message="default message",sev="info"):
 try:
  sessionKey = cherrypy.session.get('sessionKey')
  uri = "https://localhost:8089/services/messages/new"
  headers = {'Authorization':'Splunk '}
  headers['Authorization'] =  str(headers['Authorization']) + sessionKey
  data ={'name':str(title),'value':str(message),'severity':str(sev)}
  r = requests.post(uri, headers=headers, data=data, verify=False)
  if r.status_code<300:
   result = {'motd': 'true'}
   si.outputResults(result)
  else:
   logger.error(r.status_code)
   si.outputResults(result)
 except Exception, e:
  logger.exception(e)

jkat54
SplunkTrust
SplunkTrust

Ok, I was able to get it working... but not using the session from cherrypy. No clue why I cant get that session. So the example below hardcodes admin user/pass.

import sys
import re
import json
import requests
import splunk.Intersplunk 
import splunk.mining.dcutils as dcu

logger = dcu.getLogger()

help = """------------------------------------------------------------------------------------
motd title="title" message="message" severity="{warn|info|error}"
------------------------------------------------------------------------------------"""

contexthelp = """------------------------------------------------------------------------------------
motd creates a bulletin message
------------------------------------------------------------------------------------"""
def getSession(username,password):
 uri = "https://localhost:8089/services/auth/login"
 r = requests.get(uri, data={'username':username,'password':password}, verify=False)
 sessionkey = re.sub('"',"",json.dumps(re.sub('<response>\n\s+<sessionKey>|<\/sessionKey>\n<\/response>\n',"",r.text)))
 return sessionkey

def motd(results,sessionKey, title="default title",message="default message",severity="info"):
 try:
  uri = "https://localhost:8089/services/messages/new"
  #headers = {'Authorization':'Splunk '}
  headers = {'Authorization':''}
  headers['Authorization'] = 'Splunk ' + sessionKey
  data = {'name':title,'value':message,'severity':severity}
  logger.info(data)
  r = requests.post(uri, headers=headers, data=data, verify=False)
  if r.status_code<300:
   logger.info("Status Code: " + str(r.status_code))
   for result in results:
    result["motd"] = "true"
   return results
  else:
   logger.error("Status Code: " + str(r.status_code))
   for result in results:
    result["motd"] = str(r.status_code) 
   return results
 except Exception, e:
  logger.exception(e)
  logger.exception("sessionKey: " + sessionKey)
  for result in results:
   result["motd"] = e
  return results

#get the arguments
(isgetinfo, sys.argv) = splunk.Intersplunk.isGetInfo(sys.argv)
for a in sys.argv[1:]:
 if a.startswith("title="):
  title = re.sub("^.*=","",a)
  logger.info("Title: " + title)
 if a.startswith("message="):
  message = re.sub("^.*=","",a)
  logger.info("Message: " + message)
 if a.startswith("severity=warn") or a.startswith("severity=error") or a.startswith("severity=info"):
  severity = re.sub("^.*=","",a)
  logger.info("Severity: " + severity)
 elif not a.startswith("severity=warn") or not a.startswith("severity=error") or not a.startswith("severity=info"):
  severity = "info"
  logger.warn("Severity not provided, defaulting to " + severity)
 elif isgetinfo:
   splunk.Intersplunk.parseError("Invalid argument '%s'" % a)

# get the previous search results
results,dummy,settings = splunk.Intersplunk.getOrganizedResults()

#create a session key using user/pass
sessionKey = getSession("admin","password")
logger.info(sessionKey)

#set the message of the day using the arguments, all of them are optional
motd = motd(results,sessionKey,title,message,severity)

# return the previous search results
splunk.Intersplunk.outputResults(motd)


commands.conf:
[motd]
filename = motd.py

Authorize.conf:
[capability::run_script_motd]

[role_admin]
run_script_motd = enabled

Execution

* | motd __EXECUTE__ title=te555st message=testdasdfasdf3e4r severity=error

jkat54
SplunkTrust
SplunkTrust

To answer your question:

You can use requests which comes with splunk's local python27:

import requests
uri = "https://localhost:8089/services/messages/new"
username = "admin"
password = "password"
r = requests.post(uri, auth=(username, password), data={'name':'mySearch','value':'Hey ALL!','severity':'warn'}, verify=False)
page = r.text.encode('utf-8','ignore')
print page

http://docs.python-requests.org/en/latest/
https://pypi.python.org/pypi/requests

cschmidt_hurric
Path Finder

Hi, I know this is late but I just wanted to share how I solved this myself. I used requests as jkat54 suggested, but used a session key rather than a hardcoded username and password. Because this is a modular input, the session key is passed in as part of the config XML - this can be seen here: http://docs.splunk.com/Documentation/Splunk/latest/AdvancedDev/ModInputsScripts

So I modified the part of my input which parsed the config out of that XML and added a section that pulls the session key out. From there you can just add it as a header to your request:

r = requests.post(uri, headers={'Authorization': 'Splunk %s' % sessionKey}, data={'name':'mySearch','value':'Hey ALL!','severity':'warn'}, verify=False)

hirsts
Path Finder

Thanks jkat54 for responding, really appreciate your time.

The scenario is slightly different in that this is a modular input that gets distributed as an app from Splunk Base. The script that is the modular input doesnt know about any locally provisioned credentials and needs to rely on what was passed to it at the point is was invoked by splunkd.

When splunkd invokes a modular input is provides via STDIN configuration items, one of which is .

If I try an use the provided value as an authentication token to perform any REST action it fails with an authorization warning. Just for testing, if I authenticate with a locally provisioned user, capture the session token and use this token to perform the same REST action it works.

If anyone has any experience of using the splunkd provided to perform actions that would be great.

jkat54
SplunkTrust
SplunkTrust

Can you rewrite your original question providing more details?

Originally i thought you wanted a scripted input that would create a message but you didnt want to use curl because it would expose the password in curl logs, etc. So my solution was to use requests, salt, etc.

0 Karma

jkat54
SplunkTrust
SplunkTrust

I'll try it with py mod inputs but above would work as scripted input if hardcoding pass was option.

0 Karma

hirsts
Path Finder

Ok so i've done lots more digging on this and ill attempt to articulate the issue and it would seem that the "correct" way is to have the modular input script use the auth token provided when its called.

From a modular input i'm trying to get the modular input script to update https://localhost:8089/services/messages/mymessage

If I try to update endpoint with the session_key value provided by splunkd via STDIN when the modular input was called, all I get a a server response as follows:

Server response:

<msg type="WARN">call not properly authenticated</msg>

If I authenticate first with a new user that has the role "splunk-system-role" or as admin and use the session key from this login it works fine.

The documentation quotes:
" The session key for the session with splunkd. The session key can be used in any REST session with the local instance of splunkd."

Does anyone know why the provided when the modular input is called wouldn't work for /services/messages updates ?

Thanks

jkat54
SplunkTrust
SplunkTrust

are you passing an "authorization" header?

Please share your "update [to the] endpoint". Somewhere in the routine it should create a header.

headers['authorization'] = 'Splunk ' + sessionkey

This makes auth header look something like this:

Splunk xXZNyBITUTA9nQDGv0OrBZSuc4mRF3pHtFlt80ie9FSB_m7uAsA6W0V1uXchpuuvoe_BGEUG0ILiz_6bAekoyl4DGlKs9KZTE^F

jkat54
SplunkTrust
SplunkTrust

How else might you authenticate without exposing a username/pass?

Why not make a user that isnt Admin which has permission to curl the endpoint?

Why not store the password in encrypted form? SSL is used for calling the rest endpoints... you could use your own certificate for splunkd to be extra secure.

0 Karma

hirsts
Path Finder

Thanks for the ideas and ill build something using this method.

0 Karma
Get Updates on the Splunk Community!

What's new in Splunk Cloud Platform 9.1.2312?

Hi Splunky people! We are excited to share the newest updates in Splunk Cloud Platform 9.1.2312! Analysts can ...

What’s New in Splunk Security Essentials 3.8.0?

Splunk Security Essentials (SSE) is an app that can amplify the power of your existing Splunk Cloud Platform, ...

Let’s Get You Certified – Vegas-Style at .conf24

Are you ready to level up your Splunk game? Then, let’s get you certified live at .conf24 – our annual user ...