Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions bin/postversioncontrolrestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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
Expand Down Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion bin/splunkversioncontrol_backup_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
26 changes: 17 additions & 9 deletions bin/splunkversioncontrol_rest_restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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

Expand All @@ -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))
Expand All @@ -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

Expand All @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions bin/splunkversioncontrol_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
<table>
<title>SplunkVersionControl Results (please wait a few minutes for results)</title>
<search>
<query>| 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`</query>
<query>| 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`</query>
<earliest>-5m</earliest>
<latest>now</latest>
<sampleRatio>1</sampleRatio>
Expand Down
5 changes: 5 additions & 0 deletions default/macros.conf
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ iseval = 0
[sslVerify]
definition = false
iseval = 0

[requestingAddress]
definition = false
iseval = 0

38 changes: 38 additions & 0 deletions test/bkp_default.yml
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions test/certificates/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.crt
*.key
*.pem
*.csr
castuff
9 changes: 9 additions & 0 deletions test/certificates/Dockerfile
Original file line number Diff line number Diff line change
@@ -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" ]
13 changes: 13 additions & 0 deletions test/certificates/createca.sh
Original file line number Diff line number Diff line change
@@ -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

130 changes: 130 additions & 0 deletions test/certificates/createcerts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
set -e

if [ $# -ne 3 ]
then
cat <<EOF
Usage: $0 DNS_NAME IP (server_cert|usr_cert)

Example:
$0 searchhead.example.local 192.0.2.2 server_cert
EOF
exit 1
fi

HOSTNAME=$1
IP=$2
CRT_TYPE=$3

KEYOUT=$1.key
CSR=$1.csr
CERT=$1.crt
COMBINED=$1.pem

# -config <(cat openssl.conf) \
# <(printf "[SAN]\nsubjectAltName='DNS.1:${HOSTNAME},IP.1:${IP}'")


openssl req \
-newkey rsa:4096 \
-nodes \
-keyout ${KEYOUT} \
-out ${CSR} \
-config <(
cat <<-EOF
[req]
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[ dn ]
C=CH
O=Lab
OU=IT
CN=${HOSTNAME}

[ req_ext ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1=${HOSTNAME}
IP.1=${IP}
EOF
)

dir=./castuff
mkdir -p $dir/newcerts
mkdir -p $dir/crl
mkdir -p $dir/certs
[ ! -f $dir/serial ] && echo 1000 > $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}
21 changes: 21 additions & 0 deletions test/certificates/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -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 <<EOF
$(env)
EOF


echo $(env)
12 changes: 12 additions & 0 deletions test/custom_init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
set -e
sudo microdnf install git
sudo -u splunk mkdir -p /opt/splunk/vcs/{git_tmp_backup,git_tmp_restore}
if [ ! -d "/opt/splunk/vcs/backup.git" ]; then
sudo -u splunk mkdir -p /opt/splunk/vcs/backup.git
sudo -u splunk sh -c "cd /opt/splunk/vcs/backup.git && git init --bare --shared"
sudo -u splunk sh -c "cd /opt/splunk/vcs/ && git clone backup.git"
sudo -u splunk sh -c "git config --global user.email '[email protected]'"
sudo -u splunk sh -c "git config --global user.name 'BackupUser'"
sudo -u splunk sh -c 'cd /opt/splunk/vcs/backup && touch test && git add test && git commit -a -m "init" && git push'
fi
/usr/sbin/entrypoint.sh start
Loading