Skip to content

Commit 3ef37b3

Browse files
authored
Merge pull request #358 from DataIntegrationGroup/secure-db
secure-db
2 parents c217fcb + 04366e8 commit 3ef37b3

1 file changed

Lines changed: 33 additions & 4 deletions

File tree

alembic/env.py

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import copy
12
import os
23
from logging.config import fileConfig
34

45
from alembic import context
56
from dotenv import load_dotenv
67
from sqlalchemy import engine_from_config, pool, create_engine
78

9+
from services.util import get_bool_env
810

911
# this is the Alembic Config object, which provides
1012
# access to the values within the .ini file in use.
@@ -46,7 +48,10 @@ def build_database_url():
4648
user = os.environ.get("CLOUD_SQL_USER", "")
4749
password = os.environ.get("CLOUD_SQL_PASSWORD", "")
4850
database = os.environ.get("CLOUD_SQL_DATABASE", "")
51+
use_iam_auth = get_bool_env("CLOUD_SQL_IAM_AUTH", False)
4952
# Host is provided by connector, so leave blank.
53+
if use_iam_auth:
54+
return f"postgresql+pg8000://{user}@/{database}"
5055
return f"postgresql+pg8000://{user}:{password}@/{database}"
5156

5257
# Default/Postgres
@@ -96,22 +101,46 @@ def run_migrations_online() -> None:
96101
if db_driver == "cloudsql":
97102
# Use the Cloud SQL Python Connector for direct Cloud SQL access.
98103
from google.cloud.sql.connector import Connector
104+
from google.auth import default
105+
from google.auth.transport.requests import Request
99106

100107
instance_name = os.environ.get("CLOUD_SQL_INSTANCE_NAME")
101108
user = os.environ.get("CLOUD_SQL_USER")
102109
password = os.environ.get("CLOUD_SQL_PASSWORD")
103110
database = os.environ.get("CLOUD_SQL_DATABASE")
111+
use_iam_auth = get_bool_env("CLOUD_SQL_IAM_AUTH", False)
112+
ip_type = os.environ.get("CLOUD_SQL_IP_TYPE", "public")
104113

105114
connector = Connector()
106115

116+
def get_iam_login_token() -> str:
117+
scopes = ["https://www.googleapis.com/auth/sqlservice.login"]
118+
creds, _ = default()
119+
if hasattr(creds, "with_scopes"):
120+
creds = creds.with_scopes(scopes=scopes)
121+
else:
122+
creds = copy.copy(creds)
123+
creds._scopes = scopes # type: ignore[attr-defined]
124+
creds.refresh(Request())
125+
if not getattr(creds, "token", None):
126+
raise RuntimeError("Unable to acquire IAM DB auth token.")
127+
return creds.token
128+
107129
def getconn():
130+
connect_kwargs = {
131+
"user": user,
132+
"db": database,
133+
"ip_type": ip_type,
134+
"enable_iam_auth": use_iam_auth,
135+
}
136+
if use_iam_auth:
137+
connect_kwargs["password"] = get_iam_login_token()
138+
else:
139+
connect_kwargs["password"] = password
108140
return connector.connect(
109141
instance_name,
110142
"pg8000",
111-
user=user,
112-
password=password,
113-
db=database,
114-
ip_type="public",
143+
**connect_kwargs,
115144
)
116145

117146
connectable = create_engine(

0 commit comments

Comments
 (0)