diff --git a/bin/postversioncontrolrestore.py b/bin/postversioncontrolrestore.py index 73cd511..f6ca563 100644 --- a/bin/postversioncontrolrestore.py +++ b/bin/postversioncontrolrestore.py @@ -10,7 +10,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "lib")) from splunklib.searchcommands import dispatch, GeneratingCommand, Configuration, Option -from splunklib.searchcommands.validators import Validator, Boolean, File +from splunklib.searchcommands.validators import Validator, Boolean from splunklib.binding import HTTPError class OrValidator(Validator): @@ -31,6 +31,13 @@ def format(self, value): except: return self.b.format(value) +class Filename(Validator): + # TODO Validate file path + def __call__(self, value): + return value + + def format(self, value): + return value splunkLogsDir = os.environ['SPLUNK_HOME'] + "/var/log/splunk" #Setup the logging @@ -80,7 +87,8 @@ class SVCPostRestore(GeneratingCommand): restoreAsUser = Option(require=True) scope = Option(require=True) timeout = Option(require=True) - sslVerify = Option(require=False, default=False, validate=OrValidator(File(), Boolean())) + sslVerify = Option(require=False, default=False, validate=OrValidator(Boolean(), Filename())) + requestingAddress = Option(require=False, default=False) def generate(self): """ @@ -108,6 +116,8 @@ def generate(self): body['restoreAsUser'] = self.restoreAsUser body['scope'] = self.scope body['timeout'] = self.timeout + if self.requestingAddress: + body['requestingAddress'] = self.requestingAddress logger.info("Attempting POST request to url=%s with body=\"%s\"" % (url, body)) diff --git a/bin/splunkversioncontrol_backup_class.py b/bin/splunkversioncontrol_backup_class.py index 688d6ed..b2a54ea 100644 --- a/bin/splunkversioncontrol_backup_class.py +++ b/bin/splunkversioncontrol_backup_class.py @@ -1037,7 +1037,7 @@ def run_script(self): headers={'Authorization': 'Splunk %s' % config['session_key']} url = 'https://localhost:8089/services/shcluster/captain/info?output_mode=json' - res = requests.get(url, headers=headers, verify=self.sslVerify) + res = requests.get(url, headers=headers, verify=False) if (res.status_code == 503): logger.debug("i=\"%s\" Non-shcluster / standalone instance, safe to run on this node" % (self.stanzaName)) elif (res.status_code != requests.codes.ok): diff --git a/bin/splunkversioncontrol_rest_restore.py b/bin/splunkversioncontrol_rest_restore.py index 2b76e72..3142aa2 100644 --- a/bin/splunkversioncontrol_rest_restore.py +++ b/bin/splunkversioncontrol_rest_restore.py @@ -59,12 +59,15 @@ class SVCRestore(splunk.rest.BaseRestHandler): - def query_back_for_user_and_permissions(self, authorization_token, *, sslVerify): + def query_back_for_user_and_permissions(self, requestingAddress, authorization_token, *, sslVerify): headers = { "Authorization" : authorization_token } #Run a query back against the source system to check the username/role - remoteAddr = self.request['remoteAddr'] - url = "https://" + remoteAddr + ":8089/services/authentication/current-context?output_mode=json" + if requestingAddress: + remoteAddr = requestingAddress + else: + remoteAddr = "https://" + self.request['remoteAddr'] + ":8089" + url = remoteAddr + "/services/authentication/current-context?output_mode=json" logger.info("Received remote request checking username and role related to the token on url=%s" % (url)) logger.debug("token=%s" % (authorization_token)) @@ -160,7 +163,12 @@ def handle_POST(self): else: time_wait = 600 - username, roles = self.query_back_for_user_and_permissions(payload['Authorization'][0], sslVerify=sslVerify) + if 'requestingAddress' in payload: + requestingAddress = payload['requestingAddress'][0] + else: + requestingAddress = None + + username, roles = self.query_back_for_user_and_permissions(requestingAddress, payload['Authorization'][0], sslVerify=sslVerify) logger.info("username=%s roles=%s" % (username, roles)) app = payload['app'][0] @@ -207,7 +215,7 @@ def handle_POST(self): headers = { "Authorization" : "Splunk " + self.request['systemAuth'] } curtime = calendar.timegm(time.gmtime()) url = "https://localhost:8089/servicesNS/nobody/SplunkVersionControl/storage/collections/data/splunkversioncontrol_rest_restore_status" - res = self.runHttpRequest(url, headers, None, "get", "checking kvstore collection splunkversioncontrol_rest_restore_status", sslVerify=sslVerify) + res = self.runHttpRequest(url, headers, None, "get", "checking kvstore collection splunkversioncontrol_rest_restore_status", sslVerify=False) if not res: return @@ -216,14 +224,14 @@ def handle_POST(self): if not len(res) == 0: if not 'start_time' in res[0]: logger.warn("Warning invalid kvstore data, will wipe it and continue in collection splunkversioncontrol_rest_restore_status on url=%s, value returned res=\"%s\"" % (url, payload)) - self.runHttpRequest(url, headers, None, 'delete', 'wiping kvstore splunkversioncontrol_rest_restore_status', sslVerify=sslVerify) + self.runHttpRequest(url, headers, None, 'delete', 'wiping kvstore splunkversioncontrol_rest_restore_status', sslVerify=False) else: kvstore_start_time = res[0]['start_time'] target_time = curtime - time_wait if kvstore_start_time < target_time: logger.warn("Found existing entry from %s but time is %s, this is past the limit of current time minus %s (%s)" % (kvstore_start_time, curtime, time_wait, target_time)) #More than 10 minutes ago, delete the entry and move on - self.runHttpRequest(url, headers, None, "delete", "wiping kvstore splunkversioncontrol_rest_restore_status due to record %s older than %s time period" % (kvstore_start_time, target_time), sslVerify=sslVerify) + self.runHttpRequest(url, headers, None, "delete", "wiping kvstore splunkversioncontrol_rest_restore_status due to record %s older than %s time period" % (kvstore_start_time, target_time), sslVerify=False) else: removal_target = kvstore_start_time + time_wait + 1 logger.warn("Attempted to run but found a running restore instance with time=%s and current_time=%s, will delete and move on after current_time_minus=%s seconds (override_time=%s)" % (kvstore_start_time, curtime, time_wait, removal_target)) @@ -234,7 +242,7 @@ def handle_POST(self): payload = json.dumps({ 'start_time': curtime }) headers['Content-Type'] = 'application/json' #update kvstore with runtime - res = self.runHttpRequest(url, headers, payload, 'post', 'updating kvstore collection splunkversioncontrol_rest_restore_status', sslVerify=sslVerify) + res = self.runHttpRequest(url, headers, payload, 'post', 'updating kvstore collection splunkversioncontrol_rest_restore_status', sslVerify=False) if not res: return res @@ -246,7 +254,7 @@ def handle_POST(self): self.response.write("Restore has failed to complete successfully in app %s, object of type %s, with name %s, from tag %s, scope %s with restoreAsUser %s and your username of %s. Message is %s" % (app, type, obj_name, tag, scope, restoreAsUser, username, message)) logger.warn("Restore has failed to complete successfully in app=%s, object of type=%s, with name=%s, from tag=%s, scope=%s with restoreAsUser=%s and requested by username=%s, message=%s" % (app, type, obj_name, tag, scope, restoreAsUser, username, message)) - self.runHttpRequest(url, headers, None, 'delete', 'wiping kvstore splunkversioncontrol_rest_restore_status after completed run', sslVerify=sslVerify) + self.runHttpRequest(url, headers, None, 'delete', 'wiping kvstore splunkversioncontrol_rest_restore_status after completed run', sslVerify=False) #Run a Splunk query via the search/jobs endpoint def runSearchJob(self, url, appname, headers, auth, username, earliest_time, *, sslVerify=False): diff --git a/bin/splunkversioncontrol_utility.py b/bin/splunkversioncontrol_utility.py index 55689f3..0ec0b57 100644 --- a/bin/splunkversioncontrol_utility.py +++ b/bin/splunkversioncontrol_utility.py @@ -55,7 +55,7 @@ def get_password(password, session_key, logger, *, sslVerify=False): url = "https://localhost:8089/servicesNS/-/" + context + "/storage/passwords?output_mode=json&f=clear_password&search=" + password logger.debug("Trying url=%s with session_key to obtain name=%s" % (url, password)) headers = {'Authorization': 'Splunk %s' % session_key} - res = requests.get(url, headers=headers, verify=sslVerify) + res = requests.get(url, headers=headers, verify=False) dict = json.loads(res.text) clear_password = False if not 'entry' in dict: @@ -73,7 +73,7 @@ def get_password(password, session_key, logger, *, sslVerify=False): url = "https://localhost:8089/servicesNS/-/-/storage/passwords?output_mode=json&f=clear_password&count=0&search=" + password logger.debug("Trying url=%s with session_key to obtain name=%s" % (url, password)) - res = requests.get(url, headers=headers, verify=sslVerify) + res = requests.get(url, headers=headers, verify=False) dict = json.loads(res.text) if not 'entry' in dict: logger.warn("dict=%s did not contain the entries expected on url=%s while looking for password=%s" % (dict, url, password)) diff --git a/default/data/ui/views/splunkversioncontrol_restore_dynamic.xml b/default/data/ui/views/splunkversioncontrol_restore_dynamic.xml index 9a961a4..839c909 100644 --- a/default/data/ui/views/splunkversioncontrol_restore_dynamic.xml +++ b/default/data/ui/views/splunkversioncontrol_restore_dynamic.xml @@ -129,7 +129,7 @@ SplunkVersionControl Results (please wait a few minutes for results) - | postversioncontrolrestore app="$app$" obj_name="$name$" restoreAsUser="$restoreAsUser$" scope="$scope$" splunk_vc_name=`splunk_vc_name` tag="$tag$" url=`splunk_vc_url` type="$type$" timeout=`splunk_vc_timeout` sslVerify=`sslVerify` + | postversioncontrolrestore app="$app$" obj_name="$name$" restoreAsUser="$restoreAsUser$" scope="$scope$" splunk_vc_name=`splunk_vc_name` tag="$tag$" url=`splunk_vc_url` type="$type$" timeout=`splunk_vc_timeout` sslVerify=`sslVerify` requestingAddress=`requestingAddress` -5m now 1 diff --git a/default/macros.conf b/default/macros.conf index 37089d5..31c7670 100644 --- a/default/macros.conf +++ b/default/macros.conf @@ -22,3 +22,8 @@ iseval = 0 [sslVerify] definition = false iseval = 0 + +[requestingAddress] +definition = false +iseval = 0 + diff --git a/test/bkp_default.yml b/test/bkp_default.yml new file mode 100644 index 0000000..8876445 --- /dev/null +++ b/test/bkp_default.yml @@ -0,0 +1,38 @@ +--- +#ansible_post_tasks: file:///tmp/install_git.yml +splunk: + conf: + - key: inputs + value: + directory: /opt/splunk/etc/apps/SplunkVersionControl/local + content: + splunkversioncontrol_backup://SH: + srcURL: https://splunk_sh:8089 + srcUsername: admin + srcPassword: g8nGXBQBF + gitTempDir: /opt/splunk/vcs/git_tmp_backup + gitRepoURL: file:///opt/splunk/vcs/backup.git + sslVerify: /cert_dir/ca.crt + debugMode: true + useLocalAuth: false + interval: 60 + splunkversioncontrol_restore://SH: + destURL: https://splunk_sh:8089 + destUsername: admin + destPassword: g8nGXBQBF + gitTempDir: /opt/splunk/vcs/git_tmp_restore + gitRepoURL: file:///opt/splunk/vcs/backup.git + sslVerify: /cert_dir/ca.crt + debugMode: true + useLocalAuth: false + auditLogsLookupBackTime: -2h + timewait: 30 + - key: server + value: + directory: /opt/splunk/etc/system/local/ + content: + sslConfig: + enableSplunkdSSL: true + serverCert: /cert_dir/splunk_moc.pem + sslRootCAPath: /cert_dir/ca.crt + sslPassword: password diff --git a/test/certificates/.gitignore b/test/certificates/.gitignore new file mode 100644 index 0000000..423a60f --- /dev/null +++ b/test/certificates/.gitignore @@ -0,0 +1,5 @@ +*.crt +*.key +*.pem +*.csr +castuff diff --git a/test/certificates/Dockerfile b/test/certificates/Dockerfile new file mode 100644 index 0000000..411a7c2 --- /dev/null +++ b/test/certificates/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:latest + +RUN apk update && \ + apk add --no-cache openssl bash && \ + rm -rf "/var/cache/apk/*" + +COPY createca.sh createcerts.sh entrypoint.sh /scripts/ + +ENTRYPOINT [ "bash", "/scripts/entrypoint.sh" ] diff --git a/test/certificates/createca.sh b/test/certificates/createca.sh new file mode 100644 index 0000000..9491f1d --- /dev/null +++ b/test/certificates/createca.sh @@ -0,0 +1,13 @@ +set -e +CA_KEY=ca.key +CA_CRT=ca.crt +SUBJ="/C=CH/ST=Bern/L=Bern/O=Example Company/CN=CA Domain1" + +if [ ! -f $CA_KEY ]; then + openssl genrsa -out $CA_KEY 4096 +fi + +if [ ! -f $CA_CRT ]; then + openssl req -new -x509 -key ${CA_KEY} -out ${CA_CRT} -subj "$SUBJ" -days 3000 +fi + diff --git a/test/certificates/createcerts.sh b/test/certificates/createcerts.sh new file mode 100644 index 0000000..3c0a2cc --- /dev/null +++ b/test/certificates/createcerts.sh @@ -0,0 +1,130 @@ +set -e + +if [ $# -ne 3 ] + then + cat < $dir/serial +[ ! -f $dir/index.txt ] && touch $dir/index.txt +# SIGN Request +openssl ca \ + -batch \ + -in ${CSR} \ + -out ${CERT} \ + -extensions ${CRT_TYPE} \ + -config <( +cat <<-EOF +[ ca ] +default_ca = CA_default +[ CA_default ] +copy_extensions = copy +dir = . +certs = $dir/certs +crl_dir = $dir/crl +new_certs_dir = $dir/newcerts +database = $dir/index.txt +serial = $dir/serial +RANDFILE = $dir/private/.rand + +private_key = ./ca.key +certificate = ./ca.crt + +crlnumber = $dir/crlnumber +crl = $dir/crl/ca.crl.pem +crl_extensions = crl_ext +default_crl_days = 30 + +# SHA-1 is deprecated, so use SHA-2 instead. +default_md = sha256 + +name_opt = ca_default +cert_opt = ca_default +default_days = 375 +preserve = no +policy = policy_loose +unique_subject = no + +[ policy_loose ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ usr_cert ] +basicConstraints = CA:FALSE +nsCertType = client +nsComment = "Client Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth, emailProtection + +[ server_cert ] +basicConstraints = CA:FALSE +nsCertType = server +nsComment = "OpenSSL Generated Server Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth + +EOF +) + +cat ${CERT} ${KEYOUT} > ${COMBINED} +#rm ${CERT} ${CSR} ${KEYOUT} diff --git a/test/certificates/entrypoint.sh b/test/certificates/entrypoint.sh new file mode 100755 index 0000000..ede1288 --- /dev/null +++ b/test/certificates/entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/sh +set -e +echo "Starting Certificate Creation" +mkdir -p /cert_dir +cd /cert_dir +sh /scripts/createca.sh +while read -r line; do + # Get the string before = (the var name) + name="${line%=*}" + eval value="\$$name" + if [[ $name = 'CERTIFICATE'* ]] + then + echo "name: ${name}, value: ${value}" + bash /scripts/createcerts.sh ${value} + fi +done <