Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TLS support for TCP sockets #276

Merged
merged 9 commits into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,17 @@ jobs:
- name: Tests
run: |
pip install -r test-requirements.txt
py.test pymemcache/test/ -m unit,integration --port ${{ job.services.memcached.ports[11211] }}
py.test pymemcache/test/ \
-m unit,integration \
--port ${{ job.services.memcached.ports[11211] }} \
--tls-port ${{ job.services.tls_memcached.ports[11211] }}

services:
memcached:
image: memcached:latest
ports:
- 11211/tcp
tls_memcached:
image: scoriacorp/tls_memcached:latest
ports:
- 11211/tcp
jparise marked this conversation as resolved.
Show resolved Hide resolved
38 changes: 38 additions & 0 deletions extras/tls/ca-root.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-----BEGIN CERTIFICATE-----
MIIGozCCBIugAwIBAgIJAM58RO9sXvoHMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD
VQQGEwJDWjEaMBgGA1UECAwRSmlob21vcmF2c2t5IGtyYWoxDTALBgNVBAcMBEJy
bm8xGzAZBgNVBAoMElNjb3JpYSBDb3Jwb3JhdGlvbjE2MDQGA1UEAwwtU2Nvcmlh
IENvcnBvcmF0aW9uIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTIwMDQw
MzE0NDAzOVoXDTQwMDMyOTE0NDAzOVowgY0xCzAJBgNVBAYTAkNaMRowGAYDVQQI
DBFKaWhvbW9yYXZza3kga3JhajENMAsGA1UEBwwEQnJubzEbMBkGA1UECgwSU2Nv
cmlhIENvcnBvcmF0aW9uMTYwNAYDVQQDDC1TY29yaWEgQ29ycG9yYXRpb24gUm9v
dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQDJqBOt19LipwyEq8YYnWe8SOJcDSE6fc+3gSggOSisJvDcjDZfgER2
eJmVdDutRbbeHoCTlA57buIy+3Dr1BkHbWpNrSlcBD3fgja6BhDZiH6Cuq3BvL5b
y2Yin96lk5JXmjNT5SP6vBmIe68lt+2BwjHgrbI6s8vOJwOy6gGZ8rVKGR6lHtbY
S7DznswyGoDuOlzHdf/9PNfbf1Jd72qn6qpAkf7GGvzqJaxqamhtB+V4QjSuv2Ts
em61+/7aeIN+MIF7IkiyVm+FwoVz505oAoeP8obXLFi2VKifinOrTMMMIoDd9I2m
FHraS5OhmlD4XaGNV9YhOYYu/gFgiHkQyjGBjtH+a4pZPwi9SyhsBHDRWx8HsWZV
6DWLjUyUhoM9yCUUYIPv+dA6zPhs5LKsmUfM5ASuhjTN/BBx+zpTUurX6Fmnz2Io
ypfiYjGWMdrwUdMLa6pY/5RcCysJHkrVLZSQi6hiC3yPqg0TlPVYBIcGP3vbkEcU
f7MBqdH6Tc8wdSAWSc+zgVD0ql5+TZ6MUXnL5wf2NYwuuzQDa1gT/VfjOZOjkv3H
lPC8isg926R6XuywPL4CynrL/qn6DRwNVelp31aD95HBS6YAVhJg7S4odQHDar4P
bA+qXqx0+syMyF9+c6liV2fmCHMKgRFFi6SfuwmpQ92gU53bFXPa1QIDAQABo4IB
AjCB/zAdBgNVHQ4EFgQUhVz9eXfMmqIaA4m3NVpJpI1tz1AwgcIGA1UdIwSBujCB
t4AUhVz9eXfMmqIaA4m3NVpJpI1tz1ChgZOkgZAwgY0xCzAJBgNVBAYTAkNaMRow
GAYDVQQIDBFKaWhvbW9yYXZza3kga3JhajENMAsGA1UEBwwEQnJubzEbMBkGA1UE
CgwSU2NvcmlhIENvcnBvcmF0aW9uMTYwNAYDVQQDDC1TY29yaWEgQ29ycG9yYXRp
b24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDOfETvbF76BzAMBgNVHRME
BTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAHkqrlcn7pzr/
UOsWkwtJkZaUgnejrryMsS24Oj7sWmpH23ZG//97gLibAjIhngZm3AOS4K7TVxvW
rkirvaRq5ZbehOnMqLhEBbAjumK2RjeM8SBzRqYBsvU7iELyN/IMgsHzeul/5/0R
vsBr0vtI6acKOAkUfMbpxN7m/gOL2CvGUmDy1NXtHWQTeDf6wxWkNGBb4E66sK66
auSP205xxKzlMCzRaf8nfDAx7oy4zQtjJKunMtglxjrpGDCEFMixT8wqIUbf46o+
+uK2AWqprBFL42+qGiu68gzMz1WS1iMmzbM0DUmAc3piDnBOz9YZa9iMegZekch5
OL52DDd6tId/eWVFrj/IcHYoCg7KNHQteZ004zUInCpjAT/e78IZFxG8k0lZR1Lc
87s8QXfhqm/GMzDIFMdZACrH8R90ubocK06iMcTahvI5EilH6LcLut28GGrRH8Og
C0YBAPaZ5cjhflc0grSjPK1dKqj/Vre3CQH/+lJ8qTOBPurXlxFL759bsi9Auath
GZ4bWhFTnykKCXJyzFbFgJObN/r/KrU4LI8q5MrkCseX5UTZ+P345WU6ZykjQqhJ
GPi/z+dXZDy8TQJD8gg07t/oyFlzlaqDkJNWOvU+Bf/zSUyY+WxvGKXb2l9Gd7/s
e2XISxvCzZK32s1mBNWSfl/tX0iw340=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions extras/tls/client.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN CERTIFICATE-----
MIIEyzCCArOgAwIBAgIJAPPSvsWCQbfFMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD
VQQGEwJDWjEaMBgGA1UECAwRSmlob21vcmF2c2t5IGtyYWoxDTALBgNVBAcMBEJy
bm8xGzAZBgNVBAoMElNjb3JpYSBDb3Jwb3JhdGlvbjE9MDsGA1UEAww0U2Nvcmlh
IENvcnBvcmF0aW9uIENsaWVudCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eTAe
Fw0yMDA0MDMxNDQwNDBaFw0yMjA0MDMxNDQwNDBaMIGFMQswCQYDVQQGEwJDWjEa
MBgGA1UECAwRSmlob21vcmF2c2t5IGtyYWoxDTALBgNVBAcMBEJybm8xGzAZBgNV
BAoMElNjb3JpYSBDb3Jwb3JhdGlvbjEuMCwGA1UEAwwlU2NvcmlhIENvcnBvcmF0
aW9uIENsaWVudCBDZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALAJe+CxlDH9ajw9q7rpYOaXBZ7Z2t2qmRFChR9rySQVFft2mTsyeF9W
0zVNiR7wg1W74VvrrcQsv8OkbgEVeWt7e9lKIoIFzrQ1dJGUAs+vF4IQOKmlanWt
jjz42fuJVlwTn71rXHCxoyqd0jCaRd7BHtf/fl7Po9WEFRjUr5O1iZWHBIwIn7q+
edIwEUBs6qJN3vO42nqYmY7mQ/hG+vVzq7cL2WkN/EMGvj9SRVl0OMbmKnfxmUUi
FoVnB6KiREHt4Kb/4y1plZzAmEMI2QDpPp/keLSmHw55U2waTEo+BKJ//G4dp7Rs
K+CkdlOTIAEDM/AYvbM0/0rkPceovCMCAwEAAaMtMCswCQYDVR0TBAIwADARBglg
hkgBhvhCAQEEBAMCB4AwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4ICAQBV
M9wSpuC4zt5LhhXBHmxHuUVdIEIU+XXLTzMms3IC8r56rH4fFD6wfyVqvTlLVIyk
UeX/FrZ9P1uOt1H1nDeNLlK8ihVdw+JSLplCfjX7SevD8tXdnokcl95p3RMMHjXU
d46pY1StAU9fIm46WVsbtzfIPhejNlhn2L3DW3V2tkVXEKzdvaiFvmLWVlalxawY
CoyDh4m9E5s6l/B9RoLCAajSGeXQxMCm2L9DwAyUJhFPQYLO4YJT1fM7cvl7Irms
qjRAPq0rroebSP3bZDP0PXe7hwd01JcSnuLcQg6cOnsL9UOla8UpqJrMxG+rBD9o
nnIOoFA/2pjNsa0xTarRXa7C75H0f4TWlEzhsEvlTqT1eTVu/XfUcv2r2mL+jSVW
7iSQ37tlR8hN9L8/iYjIMlsf++3pdK1rvP0Mk8042pL8eqB+OYUQe/88KaNxTBeN
q1sqzkXtcJk7DqTBPXfHFJgzASpy7UR56sa/P7XmqTmBrpNDMP2XUkdNoAQjGae1
qiRmTiHP9e7d3bfWjW+odjbCxxZz5v4vfYY8FB6w2FfgLknfmnYKTOVR5ewT0d3T
01mLiKVtNDlMNHSBsOWvv72sH8Y1viQ09AzzrsCEFmyCGvQXQ4bps0ObIAITS98f
S1D9f+XM2TZJ/WxEB5VQP30iegfqEuKrwUTk8Lh6+g==
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions extras/tls/client.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAsAl74LGUMf1qPD2ruulg5pcFntna3aqZEUKFH2vJJBUV+3aZ
OzJ4X1bTNU2JHvCDVbvhW+utxCy/w6RuARV5a3t72UoiggXOtDV0kZQCz68XghA4
qaVqda2OPPjZ+4lWXBOfvWtccLGjKp3SMJpF3sEe1/9+Xs+j1YQVGNSvk7WJlYcE
jAifur550jARQGzqok3e87jaepiZjuZD+Eb69XOrtwvZaQ38Qwa+P1JFWXQ4xuYq
d/GZRSIWhWcHoqJEQe3gpv/jLWmVnMCYQwjZAOk+n+R4tKYfDnlTbBpMSj4Eon/8
bh2ntGwr4KR2U5MgAQMz8Bi9szT/SuQ9x6i8IwIDAQABAoIBAHiziATgvcQpBhaY
Eo/uRUrWcjwhFDi5KIr1GWIZ/aiH7LKm9xnn2TFFzzvVFhfowaSfVj44ssS4CiST
Mfn8R2yzFpA+jLqqULivjmXjHqpYW74KcU+g5AYcIlMcLhqSaGxp6DVwz8lVg5NM
8znwDchWkld4D6XiqWtVTUHhUyHrS74RR5KNEDSTJO+hwwWrviz9nzn5XO4vBa2C
w+SxFbQ3b4A/BCAIxEawYmBunizns29PFEgTqbmu+obRnjCHGzDH88Ob6R1uXn5f
4ofVOIGYpJi1X+0I9Io2fS9oOoaRU82gz26YLxKuE1XbZXrSchUGnfWpsVF0+yqi
TSy6cAECgYEA47OBhS1sDDg/TPwT26SVokGLhK30UxcOpxIaW9Dv+JnCGyfSffRD
BYBj2aiFLTZghJlqsumHjgRuZ4ZWW5tasioSbZ4IidIjtCkRTCv/M+eNVfaEjbZJ
Bg7uP3WnzcztYqdIbqgmyAq6ExqPr6WsICXka3SlEordOn1wuNT4NyMCgYEAxeo9
+sRyihydkNBrrcAJB5xCfPVG+THLAfUdTCZ9vC/GU31SN4CRsivvi6pwT0OKBFnz
OFjojW7Gb9c1SVgljMLubbpZfiDwT/JNzh6meEJTQnvsm3MrdNx6Zo7p2LDuOIZJ
2LQZzFKGckMxvk2xJXWHCzoBvAxecSxDe79INwECgYANE944e+dcvE5GaaPqVYWS
kBknQaZqr0RULCH/a/ycVphjXuIkAcdnpXwWoCsl8Z2RgA40wFzctzxwDbMgB8gp
u2jbitwKrlsGmeU4br51iLMBYOs0CGghRPJCCsvccgygQeNTF61Ch/sv5bKi7+z2
27ZGxahFbFxQY6v5saGf6QKBgACYTKllT8bUgTC/P6OdESnhsV14y0bSfH68AuOI
thYLurfjh4y9KTL06Nptn7rNRCvxLUb9FW3faF9LsVBQIITEzTytM7mqVa6X1t4I
v41a/a8UekiZVwcZ5pBKW6+YEI9A8BXjrLQth1Pumcatqxumt8oz2W98RghnDqjf
kVMBAoGBALbsVnmLnLiP2KnaYvYQyos8v7z43vdU1tknz04OxrMzPkBL7K0Mvk/0
yqD5jsR0cM/Fzc2RE7QBaSOkaShltIWIXlseO+kqPJ4XlLXmse3nmW8YG1ryokcG
LByhR57Kr6jHFGVcLqxrj2Bcgt6+oiCeREIjPgQMUH90W0wPM7XT
-----END RSA PRIVATE KEY-----
8 changes: 8 additions & 0 deletions extras/tls/update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

# extracting client credentials
docker run --rm scoriacorp/tls_memcached cat /opt/certs/key/client.key > client.key
docker run --rm scoriacorp/tls_memcached cat /opt/certs/crt/client.crt > client.crt

# extracting CA certificate
docker run --rm scoriacorp/tls_memcached cat /opt/certs/crt/ca-root.crt > ca-root.crt
17 changes: 14 additions & 3 deletions pymemcache/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ def __init__(self,
key_prefix=b'',
default_noreply=True,
allow_unicode_keys=False,
encoding='ascii'):
encoding='ascii',
tls_context=None):
"""
Constructor.

Expand Down Expand Up @@ -269,6 +270,7 @@ def __init__(self,
self.default_noreply = default_noreply
self.allow_unicode_keys = allow_unicode_keys
self.encoding = encoding
self.tls_context = tls_context

def check_key(self, key):
"""Checks key and add key_prefix."""
Expand All @@ -281,6 +283,11 @@ def _connect(self):
if isinstance(self.server, (list, tuple)):
sock = self.socket_module.socket(self.socket_module.AF_INET,
self.socket_module.SOCK_STREAM)

if self.tls_context:
sock = self.tls_context.wrap_socket(
sock, server_hostname=self.server[0]
)
else:
sock = self.socket_module.socket(self.socket_module.AF_UNIX,
self.socket_module.SOCK_STREAM)
Expand All @@ -291,6 +298,7 @@ def _connect(self):
if self.no_delay and sock.family == self.socket_module.AF_INET:
sock.setsockopt(self.socket_module.IPPROTO_TCP,
self.socket_module.TCP_NODELAY, 1)

except Exception:
sock.close()
raise
Expand Down Expand Up @@ -1016,7 +1024,8 @@ def __init__(self,
lock_generator=None,
default_noreply=True,
allow_unicode_keys=False,
encoding='ascii'):
encoding='ascii',
tls_context=None):
self.server = server
self.serde = serde or LegacyWrappingSerde(serializer, deserializer)
self.connect_timeout = connect_timeout
Expand All @@ -1037,6 +1046,7 @@ def __init__(self,
max_size=max_pool_size,
lock_generator=lock_generator)
self.encoding = encoding
self.tls_context = tls_context

def check_key(self, key):
"""Checks key and add key_prefix."""
Expand All @@ -1055,7 +1065,8 @@ def _create_client(self):
socket_module=self.socket_module,
key_prefix=self.key_prefix,
default_noreply=self.default_noreply,
allow_unicode_keys=self.allow_unicode_keys)
allow_unicode_keys=self.allow_unicode_keys,
tls_context=self.tls_context)
return client

def close(self):
Expand Down
7 changes: 5 additions & 2 deletions pymemcache/client/hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def __init__(
ignore_exc=False,
allow_unicode_keys=False,
default_noreply=True,
encoding='ascii'
encoding='ascii',
tls_context=None
):
"""
Constructor.
Expand Down Expand Up @@ -87,7 +88,8 @@ def __init__(
'deserializer': deserializer,
'allow_unicode_keys': allow_unicode_keys,
'default_noreply': default_noreply,
'encoding': encoding
'encoding': encoding,
'tls_context': tls_context,
}

if use_pooling is True:
Expand All @@ -99,6 +101,7 @@ def __init__(
for server, port in servers:
self.add_server(server, port)
self.encoding = encoding
self.tls_context = tls_context

def add_server(self, server, port):
key = '%s:%s' % (server, port)
Expand Down
24 changes: 24 additions & 0 deletions pymemcache/test/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
import socket
import ssl


def pytest_addoption(parser):
Expand All @@ -9,6 +10,12 @@ def pytest_addoption(parser):
parser.addoption('--port', action='store', default='11211',
help='memcached server port')

parser.addoption('--tls-server', action='store', default='localhost',
help='TLS memcached server')

parser.addoption('--tls-port', action='store', default='11212',
help='TLS memcached server port')

parser.addoption('--size', action='store', default=1024,
help='size of data in benchmarks')

Expand All @@ -29,6 +36,16 @@ def port(request):
return int(request.config.option.port)


@pytest.fixture(scope='session')
def tls_host(request):
return request.config.option.tls_server


@pytest.fixture(scope='session')
def tls_port(request):
return int(request.config.option.tls_port)


@pytest.fixture(scope='session')
def size(request):
return int(request.config.option.size)
Expand All @@ -49,6 +66,13 @@ def pairs(size, keys):
return {'pymemcache_test:%d' % i: 'X' * size for i in range(keys)}


@pytest.fixture(scope='session')
def tls_context():
return ssl.create_default_context(
cafile="extras/tls/ca-root.crt"
)


def pytest_generate_tests(metafunc):
if 'socket_module' in metafunc.fixturenames:
socket_modules = [socket]
Expand Down
16 changes: 16 additions & 0 deletions pymemcache/test/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,19 @@ def _unicode_value_in_set():

with pytest.raises(MemcacheClientError):
_unicode_value_in_set()


@pytest.mark.integration()
def test_tls(client_class, tls_host, tls_port, socket_module, tls_context):
client = client_class(
(tls_host, tls_port),
socket_module=socket_module,
tls_context=tls_context
)
client.flush_all()

key = b'key'
value = b'value'
key2 = b'key2'
value2 = b'value2'
get_set_helper(client, key, value, key2, value2)