Homeserver Whitlisting

pull/5544/head
Jorik Schellekens 2019-06-25 18:16:48 +01:00
parent 088176e5b2
commit dde461814d
5 changed files with 110 additions and 47 deletions

View File

@ -18,6 +18,7 @@ import logging
from jaeger_client import Config as JaegerConfig
from synapse.util.scopecontextmanager import LogContextScopeManager
from synapse.util.tracerutils import TracerUtil
from ._base import Config, ConfigError
@ -37,7 +38,7 @@ class TracerConfig(Config):
# If no whitelists are given
self.tracer_config.setdefault("homeserver_whitelist", [])
if isinstance(self.tracer_config.get("homeserver_whitelist"), list):
if not isinstance(self.tracer_config.get("homeserver_whitelist"), list):
raise ConfigError("Tracer homesererver_whitelist config is malformed")
def generate_config_section(cls, **kwargs):
@ -55,7 +56,7 @@ class TracerConfig(Config):
def init_tracing(config):
"""Initialise the JaegerClient tracer
"""Set the whitelists and initialise the JaegerClient tracer
Args:
config (Config)
@ -64,6 +65,9 @@ def init_tracing(config):
"""
if config.tracer_config.get("tracer_enabled", False):
TracerUtil.set_homeserver_whitelist(
config.tracer_config["homeserver_whitelist"]
)
jaeger_config = JaegerConfig(
config={"sampler": {"type": "const", "param": 1}, "logging": True},
service_name=config.server_name,

View File

@ -23,8 +23,6 @@ from six import PY3, raise_from, string_types
from six.moves import urllib
import attr
import opentracing
from opentracing import tags
import treq
from canonicaljson import encode_canonical_json
from opentracing.propagation import Format
@ -39,6 +37,10 @@ from twisted.internet.task import _EPSILON, Cooperator
from twisted.web._newclient import ResponseDone
from twisted.web.http_headers import Headers
import opentracing
from opentracing import tags
from synapse.util.tracerutils import TracerUtil
import synapse.metrics
import synapse.util.retryutils
from synapse.api.errors import (
@ -356,8 +358,9 @@ class MatrixFederationHttpClient(object):
# Inject the span into the headers
headers_dict = {}
opentracing.tracer.inject(scope.span, Format.HTTP_HEADERS, headers_dict)
headers_dict = {k.encode(): [v.encode()] for k, v in headers_dict.items()}
TracerUtil.inject_span_context_byte_dict(
headers_dict, scope.span, request.destination
)
headers_dict[b"User-Agent"] = [self.version_string_bytes]

View File

@ -23,7 +23,7 @@ from twisted.web.server import Request, Site
from synapse.http import redact_uri
from synapse.http.request_metrics import RequestMetrics, requests_counter
from synapse.util.logcontext import LoggingContext, PreserveLoggingContext
from synapse.util.tracerutils import extract_span_context
from synapse.util.tracerutils import TracerUtil
logger = logging.getLogger(__name__)
@ -239,7 +239,7 @@ class SynapseRequest(Request):
)
# Start a span
span_context = extract_span_context(self.requestHeaders)
span_context = TracerUtil.extract_span_context(self.requestHeaders)
opentracing.tracer.start_active_span(
"incoming-federation-request",
tags={

View File

@ -86,9 +86,6 @@ class LogContextScopeManager(ScopeManager):
ctx.scope = scope
return scope
def request_from_whitelisted_homeserver(self, request):
pass
class _LogContextScope(Scope):
"""

View File

@ -13,51 +13,110 @@
# See the License for the specific language governing permissions and
# limitations under the License.import opentracing
import logging
logger = logging.getLogger(__name__)
import opentracing
from opentracing.propagation import Format
import re
def extract_span_context(headers):
"""
Extracts a span context from Twisted Headers.
args:
headers (twisted.web.http_headers.Headers)
returns:
span_context (opentracing.span.SpanContext)
"""
# Twisted encodes the values as lists whereas opentracing doesn't.
# So, we take the first item in the list.
# Also, twisted uses byte arrays while opentracing expects strings.
header_dict = {k.decode(): v[0].decode() for k, v in headers.getAllRawHeaders()}
return opentracing.tracer.extract(Format.HTTP_HEADERS, header_dict)
# block everything by default
def inject_span_context(headers, span):
"""
Injects a span context into twisted headers inplace
args:
headers (twisted.web.http_headers.Headers)
span (opentracing.Span)
class TracerUtil:
_homeserver_whitelist = None
note:
The headers set by the tracer are custom to the tracer implementation which
should be unique enough that they don't interfere with any headers set by
synapse or twisted. If we're still using jaeger these headers would be those
here:
https://github.com/jaegertracing/jaeger-client-python/blob/master/jaeger_client/constants.py
"""
carrier = {}
carrier = opentracing.tracer.inject(span, Format.HTTP_HEADERS, {})
@staticmethod
def set_homeserver_whitelist(homeserver_whitelist):
"""Sets the whitelist
for key, value in carrier:
headers.addRawHeaders(key, value)
Args:
homeserver_whitelist (iterable of strings): regex of whitelisted homeservers
"""
if homeserver_whitelist:
# Makes a single regex which accepts all passed in regexes in the list
TracerUtil._homeserver_whitelist = re.compile(
"({})".format(")|(".join(homeserver_whitelist))
)
logger.info("Set whitelist to {}".format(TracerUtil._homeserver_whitelist))
@staticmethod
def whitelisted_homeserver(destination):
if TracerUtil._homeserver_whitelist:
return TracerUtil._homeserver_whitelist.match(destination)
return False
# TODO: Implement whitelisting
def request_from_whitelisted_homeserver(request):
pass
@staticmethod
def extract_span_context(headers):
"""
Extracts a span context from Twisted Headers.
args:
headers (twisted.web.http_headers.Headers)
returns:
span_context (opentracing.span.SpanContext)
"""
# Twisted encodes the values as lists whereas opentracing doesn't.
# So, we take the first item in the list.
# Also, twisted uses byte arrays while opentracing expects strings.
header_dict = {k.decode(): v[0].decode() for k, v in headers.getAllRawHeaders()}
return opentracing.tracer.extract(Format.HTTP_HEADERS, header_dict)
@staticmethod
def inject_span_context(headers, span, destination):
"""
Injects a span context into twisted headers inplace
# TODO: Implement whitelisting
def user_whitelisted(request):
pass
Args:
headers (twisted.web.http_headers.Headers)
span (opentracing.Span)
Returns:
Inplace modification of headers
Note:
The headers set by the tracer are custom to the tracer implementation which
should be unique enough that they don't interfere with any headers set by
synapse or twisted. If we're still using jaeger these headers would be those
here:
https://github.com/jaegertracing/jaeger-client-python/blob/master/jaeger_client/constants.py
"""
if not TracerUtil.whitelisted_homeserver(destination):
return
carrier = {}
opentracing.tracer.inject(span, Format.HTTP_HEADERS, carrier)
for key, value in carrier.items():
headers.addRawHeaders(key, value)
@staticmethod
def inject_span_context_byte_dict(headers, span, destination):
"""
Injects a span context into a dict where the headers are encoded as byte
strings
Args:
headers (dict)
span (opentracing.Span)
Returns:
Inplace modification of headers
Note:
The headers set by the tracer are custom to the tracer implementation which
should be unique enough that they don't interfere with any headers set by
synapse or twisted. If we're still using jaeger these headers would be those
here:
https://github.com/jaegertracing/jaeger-client-python/blob/master/jaeger_client/constants.py
"""
if not TracerUtil.whitelisted_homeserver(destination):
logger.info("{}".format(TracerUtil._homeserver_whitelist))
return
carrier = {}
opentracing.tracer.inject(span, Format.HTTP_HEADERS, carrier)
for key, value in carrier.items():
headers[key.encode()] = [value.encode()]