From cfcc3128c28495161d1ea12cd2637a85c115f621 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Mon, 9 Nov 2020 10:40:58 +0000 Subject: [PATCH] db: specify sslmode in Cloud Foundry env Refer to https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-CONNECT-SSLMODE GOV.UK PaaS gives us the database URI, and we use the default mode of postgres auth which prefers a TLS connection instead of a plain TCP connection We are now specifying the SSL mode in the URI when establishing our connection to the database, so that: * We will not connect to the database via a plaintext connection * We will verify the database connection against a list of trusted CAs The RDS CA from which the database's certificate is issued is added into the Cloud Foundry app container via https://github.com/alphagov/paas-cf/blob/925681f19bbf9d442298fbfa93d18804a7e150eb/manifests/cf-manifest/operations.d/350-diego-cell.yml#L17-L22 Signed-off-by: Toby Lorne Co-authored-by: David --- app/cloudfoundry_config.py | 7 +++++- tests/app/test_cloudfoundry_config.py | 33 ++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/app/cloudfoundry_config.py b/app/cloudfoundry_config.py index 5cb7c437f..d886f676f 100644 --- a/app/cloudfoundry_config.py +++ b/app/cloudfoundry_config.py @@ -14,7 +14,12 @@ def extract_cloudfoundry_config(): def set_config_env_vars(vcap_services): # Postgres config - os.environ['SQLALCHEMY_DATABASE_URI'] = vcap_services['postgres'][0]['credentials']['uri'] + db_uri = vcap_services['postgres'][0]['credentials']['uri'] + + sep = "&" if "?" in db_uri else "?" + db_uri += sep + "sslmode=verify-full" + + os.environ['SQLALCHEMY_DATABASE_URI'] = db_uri vcap_application = json.loads(os.environ['VCAP_APPLICATION']) os.environ['NOTIFY_ENVIRONMENT'] = vcap_application['space_name'] diff --git a/tests/app/test_cloudfoundry_config.py b/tests/app/test_cloudfoundry_config.py index 8e1e5b158..3d6331a80 100644 --- a/tests/app/test_cloudfoundry_config.py +++ b/tests/app/test_cloudfoundry_config.py @@ -31,10 +31,35 @@ def cloudfoundry_environ(os_environ, cloudfoundry_config): os.environ['VCAP_APPLICATION'] = '{"space_name": "🚀🌌"}' +@pytest.fixture +def postgres_config_with_setting(): + return [ + { + 'credentials': { + 'uri': 'postgres uri?setting=true' + } + } + ] + + +@pytest.fixture +def cloudfoundry_config_with_setting(postgres_config_with_setting): + return { + 'postgres': postgres_config_with_setting, + 'user-provided': [] + } + + +@pytest.fixture +def cloudfoundry_environ_with_setting(os_environ, cloudfoundry_config_with_setting): + os.environ['VCAP_SERVICES'] = json.dumps(cloudfoundry_config_with_setting) + os.environ['VCAP_APPLICATION'] = '{"space_name": "🚀🌌"}' + + def test_extract_cloudfoundry_config_populates_other_vars(cloudfoundry_environ): extract_cloudfoundry_config() - assert os.environ['SQLALCHEMY_DATABASE_URI'] == 'postgres uri' + assert os.environ['SQLALCHEMY_DATABASE_URI'] == 'postgres uri?sslmode=verify-full' assert os.environ['NOTIFY_ENVIRONMENT'] == '🚀🌌' assert os.environ['NOTIFY_LOG_PATH'] == '/home/vcap/logs/app.log' @@ -49,3 +74,9 @@ def test_set_config_env_vars_ignores_unknown_configs(cloudfoundry_config, cloudf assert 'foo' not in os.environ assert 'bar' not in os.environ + + +def test_extract_cloudfoundry_config_populates_postgres_with_setting(cloudfoundry_environ_with_setting): + extract_cloudfoundry_config() + + assert os.environ['SQLALCHEMY_DATABASE_URI'] == 'postgres uri?setting=true&sslmode=verify-full'