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
8 changes: 7 additions & 1 deletion instana/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Agent(object):
last_fork_check = None
_boot_pid = os.getpid()
extra_headers = None
secrets_matcher = 'contains-ignore-case'
secrets_list = ['key', 'password', 'secret']
client = requests.Session()

def __init__(self):
Expand Down Expand Up @@ -69,7 +71,7 @@ def can_send(self):
self.handle_fork()
return False

if (self.fsm.fsm.current == "good2go"):
if self.fsm.fsm.current == "good2go":
return True

return False
Expand All @@ -82,6 +84,10 @@ def set_from(self, json_string):

res_data = json.loads(raw_json)

if "secrets" in res_data:
self.secrets_matcher = res_data['secrets']['matcher']
self.secrets_list = res_data['secrets']['list']

if "extraHeaders" in res_data:
self.extra_headers = res_data['extraHeaders']
logger.info("Will also capture these custom headers: %s", self.extra_headers)
Expand Down
4 changes: 3 additions & 1 deletion instana/instrumentation/django/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ...log import logger
from ...singletons import agent, tracer
from ...util import strip_secrets

DJ_INSTANA_MIDDLEWARE = 'instana.instrumentation.django.middleware.InstanaMiddleware'

Expand Down Expand Up @@ -44,7 +45,8 @@ def process_request(self, request):
if 'PATH_INFO' in env:
request.iscope.span.set_tag(ext.HTTP_URL, env['PATH_INFO'])
if 'QUERY_STRING' in env and len(env['QUERY_STRING']):
request.iscope.span.set_tag("http.params", env['QUERY_STRING'])
scrubbed_params = strip_secrets(env['QUERY_STRING'], agent.secrets_matcher, agent.secrets_list)
request.iscope.span.set_tag("http.params", scrubbed_params)
if 'HTTP_HOST' in env:
request.iscope.span.set_tag("http.host", env['HTTP_HOST'])
except Exception:
Expand Down
8 changes: 6 additions & 2 deletions instana/instrumentation/urllib3.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import wrapt

from ..log import logger
from ..singletons import tracer
from ..singletons import agent, tracer
from ..util import strip_secrets

try:
import urllib3 # noqa
Expand All @@ -20,13 +21,16 @@ def collect(instance, args, kwargs):

if args is not None and len(args) is 2:
kvs['method'] = args[0]
kvs['path'] = args[1]
kvs['path'] = strip_secrets(args[1], agent.secrets_matcher, agent.secrets_list)
else:
kvs['method'] = kwargs.get('method')
kvs['path'] = kwargs.get('path')
if kvs['path'] is None:
kvs['path'] = kwargs.get('url')

# Strip any secrets from potential query params
kvs['path'] = strip_secrets(kvs['path'], agent.secrets_matcher, agent.secrets_list)

if type(instance) is urllib3.connectionpool.HTTPSConnectionPool:
kvs['url'] = 'https://%s:%d%s' % (kvs['host'], kvs['port'], kvs['path'])
else:
Expand Down
1 change: 1 addition & 0 deletions instana/json_span.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def __init__(self, **kwds):
class HttpData(object):
host = None
url = None
params = None
status = 0
method = None
path_tpl = None
Expand Down
2 changes: 1 addition & 1 deletion instana/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def build_registered_span(self, span):
if span.operation_name in self.http_spans:
data.http = HttpData(host=self.get_http_host_name(span),
url=span.tags.pop(ext.HTTP_URL, None),
params=span.tags.pop('http.params', None),
method=span.tags.pop(ext.HTTP_METHOD, None),
status=span.tags.pop(ext.HTTP_STATUS_CODE, None),
path_tpl=span.tags.pop("http.path_tpl", None),
Expand All @@ -129,7 +130,6 @@ def build_registered_span(self, span):
url=span.tags.pop('sqlalchemy.url', None),
err=span.tags.pop('sqlalchemy.err', None))


if span.operation_name == "soap":
data.soap = SoapData(action=span.tags.pop('soap.action', None))

Expand Down
2 changes: 1 addition & 1 deletion instana/singletons.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
#
tracer = InstanaTracer()

# Set ourselves as the tracer.
# Set ourselves as the tracer.
opentracing.tracer = tracer
85 changes: 81 additions & 4 deletions instana/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import time

import pkg_resources
from urllib import parse

from .log import logger


if sys.version_info.major is 2:
string_types = basestring
else:
Expand All @@ -28,7 +30,7 @@ def generate_id():
global _current_pid

pid = os.getpid()
if (_current_pid != pid):
if _current_pid != pid:
_current_pid = pid
_rnd.seed(int(1000000 * time.time()) ^ pid)
return _rnd.randint(-9223372036854775808, 9223372036854775807)
Expand All @@ -41,8 +43,8 @@ def id_to_header(id):
if not isinstance(id, int):
return BAD_ID_HEADER

byteString = struct.pack('>q', id)
return str(binascii.hexlify(byteString).decode('UTF-8').lstrip('0'))
byte_string = struct.pack('>q', id)
return str(binascii.hexlify(byte_string).decode('UTF-8').lstrip('0'))
except Exception as e:
logger.debug(e)
return BAD_ID_HEADER
Expand Down Expand Up @@ -75,15 +77,90 @@ def to_json(obj):


def package_version():
version = ""
try:
version = ""
version = pkg_resources.get_distribution('instana').version
except pkg_resources.DistributionNotFound:
version = 'unknown'
finally:
return version


def strip_secrets(qp, matcher, kwlist):
"""
This function will scrub the secrets from a query param string based on the passed in matcher and kwlist.

blah=1&secret=password&valid=true will result in blah=1&secret=<redacted>&valid=true

You can even pass in path query combinations:

/signup?blah=1&secret=password&valid=true will result in /signup?blah=1&secret=<redacted>&valid=true

:param qp: a string representing the query params in URL form (unencoded)
:param matcher: the matcher to use
:param kwlist: the list of keywords to match
:return: a scrubbed query param string
"""
path = None

try:
if qp is None:
return ''

if type(kwlist) is not list:
logger.debug("strip_secrets: bad keyword list")
return qp

# If there are no key=values, then just return
if not '=' in qp:
return qp

if '?' in qp:
path, query = qp.split('?')
else:
query = qp

params = parse.parse_qs(query, keep_blank_values=True)
redacted = ['<redacted>']

if matcher == 'equals-ignore-case':
for keyword in kwlist:
for key in params.keys():
if key.lower() == keyword.lower():
params[key] = redacted
elif matcher == 'equals':
for keyword in kwlist:
if keyword in params:
params[keyword] = redacted
elif matcher == 'contains-ignore-case':
for keyword in kwlist:
for key in params.keys():
if keyword.lower() in key.lower():
params[key] = redacted
elif matcher == 'contains':
for keyword in kwlist:
for key in params.keys():
if keyword in key:
params[key] = redacted
elif matcher == 'regex':
for regexp in kwlist:
for key in params.keys():
if re.match(regexp, key):
params[key] = redacted
else:
logger.debug("strip_secrets: unknown matcher")
return qp

result = parse.urlencode(params, doseq=True)
query = parse.unquote(result)

if path:
query = path + '?' + query

return query
except:
logger.debug("strip_secrets", exc_info=True)

def get_py_source(file):
"""
Retrieves and returns the source code for any Python
Expand Down
4 changes: 3 additions & 1 deletion instana/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import opentracing.ext.tags as tags

from .singletons import agent, tracer
from .util import strip_secrets


class iWSGIMiddleware(object):
Expand Down Expand Up @@ -47,7 +48,8 @@ def new_start_response(status, headers, exc_info=None):
if 'PATH_INFO' in env:
self.scope.span.set_tag(tags.HTTP_URL, env['PATH_INFO'])
if 'QUERY_STRING' in env and len(env['QUERY_STRING']):
self.scope.span.set_tag("http.params", env['QUERY_STRING'])
scrubbed_params = strip_secrets(env['QUERY_STRING'], agent.secrets_matcher, agent.secrets_list)
self.scope.span.set_tag("http.params", scrubbed_params)
if 'REQUEST_METHOD' in env:
self.scope.span.set_tag(tags.HTTP_METHOD, env['REQUEST_METHOD'])
if 'HTTP_HOST' in env:
Expand Down
Loading