Skip to content

Commit e82da11

Browse files
authored
Configurable SSL Connection (Netflix#373)
* [TRIS-297] Configurable SSL Connection (#1) * Configurable SSL connection * Update services/utils/__init__.py * no ssl unit testing (#3) * ssl seperate test (Netflix#4) * dsn generator sslmode none (Netflix#5)
1 parent a1cd81a commit e82da11

File tree

4 files changed

+68
-17
lines changed

4 files changed

+68
-17
lines changed

run_goose.py

+21-7
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,27 @@ def main():
5151
parser.add_argument("--wait", type=int, default=30, help="Wait for connection for X seconds")
5252
args = parser.parse_args()
5353

54-
db_connection_string = "postgresql://{}:{}@{}:{}/{}?sslmode=disable".format(
55-
quote(os.environ["MF_METADATA_DB_USER"]),
56-
quote(os.environ["MF_METADATA_DB_PSWD"]),
57-
os.environ["MF_METADATA_DB_HOST"],
58-
os.environ["MF_METADATA_DB_PORT"],
59-
os.environ["MF_METADATA_DB_NAME"],
60-
)
54+
db_connection_string = f'postgresql://{quote(os.environ["MF_METADATA_DB_USER"])}:'\
55+
f'{quote(os.environ["MF_METADATA_DB_PSWD"])}@{os.environ["MF_METADATA_DB_HOST"]}:'\
56+
f'{os.environ["MF_METADATA_DB_PORT"]}/{os.environ["MF_METADATA_DB_NAME"]}'
57+
58+
ssl_mode = os.environ["MF_METADATA_DB_SSL_MODE"]
59+
ssl_cert_path = os.environ["MF_METADATA_DB_SSL_CERT_PATH"]
60+
ssl_key_path = os.environ["MF_METADATA_DB_SSL_KEY_PATH"]
61+
ssl_root_cert_path = os.environ["MF_METADATA_DB_SSL_ROOT_CERT"]
62+
63+
if (ssl_mode in ['allow', 'prefer', 'require', 'verify-ca', 'verify-full']):
64+
ssl_query = f'ssl_mode={ssl_mode}'
65+
if ssl_cert_path is not None:
66+
ssl_query = f'{ssl_query}&sslcert={ssl_cert_path}'
67+
if ssl_key_path is not None:
68+
ssl_query = f'{ssl_query}&sslkey={ssl_key_path}'
69+
if ssl_root_cert_path is not None:
70+
ssl_query = f'{ssl_query}&sslrootcert={ssl_root_cert_path}'
71+
else:
72+
ssl_query = f'sslmode=disable'
73+
74+
db_connection_string = f'{db_connection_string}?{ssl_query}'
6175

6276
if args.wait:
6377
wait_for_postgres(db_connection_string, timeout_seconds=args.wait)

services/utils/__init__.py

+42-9
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ def __init__(self,
193193
user: str = "postgres",
194194
password: str = "postgres",
195195
database_name: str = "postgres",
196+
ssl_mode: str = "disabled",
197+
ssl_cert_path: str = None,
198+
ssl_key_path: str = None,
199+
ssl_root_cert_path: str = None,
196200
prefix="MF_METADATA_DB_",
197201
pool_min: int = 1,
198202
pool_max: int = 10,
@@ -209,6 +213,10 @@ def __init__(self,
209213
self._user = os.environ.get(prefix + "USER", user)
210214
self._password = os.environ.get(prefix + "PSWD", password)
211215
self._database_name = os.environ.get(prefix + "NAME", database_name)
216+
self._ssl_mode = os.environ.get(prefix + "SSL_MODE", ssl_mode)
217+
self._ssl_cert_path = os.environ.get(prefix + "SSL_CERT_PATH", ssl_cert_path)
218+
self._ssl_key_path = os.environ.get(prefix + "SSL_KEY_PATH", ssl_key_path),
219+
self._ssl_root_cert_path = os.environ.get(prefix + "SSL_ROOT_CERT_PATH", ssl_root_cert_path)
212220
conn_str_required_values = [
213221
self._host,
214222
self._port,
@@ -247,19 +255,44 @@ def _is_valid_dsn(dsn):
247255

248256
@property
249257
def connection_string_url(self):
250-
# postgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...]
251-
return f'postgresql://{quote(self._user)}:{quote(self._password)}@{self._host}:{self._port}/{self._database_name}?sslmode=disable'
258+
base_url = f'postgresql://{quote(self._user)}:{quote(self._password)}@{self._host}:{self._port}/{self._database_name}'
259+
if (self._ssl_mode in ['allow', 'prefer', 'require', 'verify-ca', 'verify-full']):
260+
ssl_query = f'sslmode={self._ssl_mode}'
261+
if self._ssl_cert_path is not None:
262+
ssl_query = f'{ssl_query}&sslcert={self._ssl_cert_path}'
263+
if self._ssl_key_path is not None:
264+
ssl_query = f'{ssl_query}&sslkey={self._ssl_key_path}'
265+
if self._ssl_root_cert_path is not None:
266+
ssl_query = f'{ssl_query}&sslrootcert={self._ssl_root_cert_path}'
267+
else:
268+
ssl_query = f'sslmode=disable'
269+
270+
return f'{base_url}?{ssl_query}'
252271

253272
@property
254273
def dsn(self):
255274
if self._dsn is None:
256-
return psycopg2.extensions.make_dsn(
257-
dbname=self._database_name,
258-
user=self._user,
259-
host=self._host,
260-
port=self._port,
261-
password=self._password
262-
)
275+
ssl_mode = self._ssl_mode
276+
sslcert = self._ssl_cert_path
277+
sslkey = self._ssl_key_path
278+
sslrootcert = self._ssl_root_cert_path
279+
if (ssl_mode not in ['allow', 'prefer', 'require', 'verify-ca', 'verify-full']):
280+
ssl_mode = None
281+
sslcert = None
282+
sslkey = None
283+
sslrootcert = None
284+
kwargs = {
285+
'dbname': self._database_name,
286+
'user': self._user,
287+
'host': self._host,
288+
'port': self._port,
289+
'password': self._password,
290+
'sslmode': ssl_mode,
291+
'sslcert': sslcert,
292+
'sslkey': sslkey,
293+
'sslrootcert': sslrootcert
294+
}
295+
return psycopg2.extensions.make_dsn(**{k: v for k, v in kwargs.items() if v is not None})
263296
else:
264297
return self._dsn
265298

services/utils/tests/unit_tests/utils_test.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ def test_db_conf_env_dsn():
125125
with set_env({'MF_METADATA_DB_DSN': 'dbname=testgres user=test_user host=test_host port=1234 password=test_pwd'}):
126126
# valid DSN in env should set correctly.
127127
assert DBConfiguration().dsn == 'dbname=testgres user=test_user host=test_host port=1234 password=test_pwd'
128-
128+
129+
with set_env({'MF_METADATA_DB_DSN': 'dbname=testgres user=test_user host=test_host port=1234 password=test_pwd sslmode=verify-full sslrootcert=/test'}):
130+
# valid DSN in env should set correctly.
131+
assert DBConfiguration().dsn == 'dbname=testgres user=test_user host=test_host port=1234 password=test_pwd sslmode=verify-full sslrootcert=/test'
129132

130133
def test_db_conf_pool_size():
131134
with set_env():

tox.ini

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ commands = pytest --cov=services -m unit_tests
1717

1818
[testenv:integration]
1919
commands = pytest --cov=services -m integration_tests
20+

0 commit comments

Comments
 (0)