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

fix: throw error if Auto IAM AuthN is unsupported #476

Merged
merged 12 commits into from
Sep 22, 2022
29 changes: 24 additions & 5 deletions google/cloud/sql/connector/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ def __init__(self, *args: Any) -> None:
super(ExpiredInstanceMetadata, self).__init__(self, *args)


class AutoIAMAuthNotSupported(Exception):
"""
Exception to be raised when Automatic IAM Authentication is not
supported with database engine version.
"""

pass


class InstanceMetadata:
ip_addrs: Dict[str, Any]
context: ssl.SSLContext
Expand All @@ -115,7 +124,6 @@ def __init__(
enable_iam_auth: bool,
) -> None:
self.ip_addrs = ip_addrs

self.context = ssl.SSLContext(ssl.PROTOCOL_TLS)

# verify OpenSSL version supports TLSv1.3
Expand Down Expand Up @@ -366,10 +374,21 @@ async def _perform_refresh(self) -> InstanceMetadata:
self._enable_iam_auth,
)
)

metadata, ephemeral_cert = await asyncio.gather(
metadata_task, ephemeral_task
)
try:
metadata = await metadata_task
# check if automatic IAM database authn is supported for database engine
if self._enable_iam_auth and not metadata[
"database_version"
].startswith("POSTGRES"):
raise AutoIAMAuthNotSupported(
f"'{metadata['database_version']}' does not support automatic IAM authentication. It is only supported with Cloud SQL Postgres instances."
)
except Exception:
# cancel ephemeral cert task if exception occurs before it is awaited
ephemeral_task.cancel()
raise

ephemeral_cert = await ephemeral_task

x509 = load_pem_x509_certificate(
ephemeral_cert.encode("UTF-8"), default_backend()
Expand Down
1 change: 1 addition & 0 deletions google/cloud/sql/connector/refresh_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ async def _get_metadata(
metadata = {
"ip_addresses": {ip["type"]: ip["ipAddress"] for ip in ret_dict["ipAddresses"]},
"server_ca_cert": ret_dict["serverCaCert"]["cert"],
"database_version": ret_dict["databaseVersion"],
}

return metadata
Expand Down
33 changes: 33 additions & 0 deletions tests/system/test_connector_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
"""
import asyncio
import os
import pytest
import pymysql
import sqlalchemy
import logging
import google.auth
from google.cloud.sql.connector import Connector
from google.cloud.sql.connector.instance import AutoIAMAuthNotSupported
import datetime
import concurrent.futures
from threading import Thread
Expand Down Expand Up @@ -141,3 +143,34 @@ def test_connector_with_custom_loop() -> None:
assert result[0] == 1
# assert that Connector does not start its own thread
assert connector._thread is None


def test_connector_mysql_iam_auth_error() -> None:
"""
Test that connecting with enable_iam_auth set to True
for MySQL raises exception.
"""
with pytest.raises(AutoIAMAuthNotSupported):
with Connector(enable_iam_auth=True) as connector:
connector.connect(
os.environ["MYSQL_CONNECTION_NAME"],
"pymysql",
user="my-user",
db="my-db",
)


def test_connector_sqlserver_iam_auth_error() -> None:
"""
Test that connecting with enable_iam_auth set to True
for SQL Server raises exception.
"""
with pytest.raises(AutoIAMAuthNotSupported):
with Connector(enable_iam_auth=True) as connector:
connector.connect(
os.environ["SQLSERVER_CONNECTION_NAME"],
"pytds",
user="my-user",
password="my-pass",
db="my-db",
)