From 2d3c4280a7d595c152a6d7b16e63b780d5d8fb74 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 18 Sep 2026 12:18:56 +0200 Subject: [PATCH 1/2] Connect to SQL with the driver's certificate validation instead of disabling it The connection string no longer carries TrustServerCertificate. Its default is already "no" in ODBC Driver 18, so the driver validates the server certificate, which is what Microsoft recommends: "Install a certificate on the server that the client trusts. This option is the recommended one, and it's the only one that keeps both encryption and validation" (https://learn.microsoft.com/sql/connect/odbc/major-version-differences#encryption-changes). Keeping the keyword at its default value only obscured that the sample was opting out of validation. This works against LocalStack for Azure because the emulator now serves a publicly trusted certificate for the host name it returns in fullyQualifiedDomainName, so the sample no longer needs a local exception to run. The same keyword is gone from the connection string that deploy.sh stores in Key Vault, since the app reads that value. Verified end to end on both targets, with the sample otherwise unchanged: - Real Azure: deploy.sh and validate.sh exit 0, and https://.azurewebsites.net returns the app's own page with 9 cells rendered from the Azure SQL database. - LocalStack for Azure: deploy.sh and validate.sh exit 0, and the app answers on the emulator endpoint with the same page and the same 9 cells. If LocalStack cannot download its public certificate (for example with SKIP_SSL_CERT_DOWNLOAD=1) the server presents a certificate issued by the LocalStack root certificate authority, and a client then needs that authority installed or TrustServerCertificate=yes. The code comment says so. Co-Authored-By: Claude Opus 5 (1M context) --- .../web-app-sql-database/python/src/database.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/samples/web-app-sql-database/python/src/database.py b/samples/web-app-sql-database/python/src/database.py index cd3d3d6..8c2cc7f 100644 --- a/samples/web-app-sql-database/python/src/database.py +++ b/samples/web-app-sql-database/python/src/database.py @@ -166,15 +166,17 @@ def _build_connection_string(self) -> str: f"Server=tcp:{self.server},1433;" f"Database={self.database};" f"Encrypt=yes;" - f"TrustServerCertificate=yes;" f"Connection Timeout={self.connection_timeout};" ) - # TrustServerCertificate=yes tells the ODBC driver to accept self-signed certificates without verification - # This is appropriate for: - # - Local development with Docker containers - # - Testing environments with self-signed certificates - # - Internal networks where you control the SQL Server + # TrustServerCertificate is deliberately absent: its default is already "no" in ODBC Driver 18, + # so the driver validates the server certificate, which is what Microsoft recommends + # (https://learn.microsoft.com/sql/connect/odbc/major-version-differences#encryption-changes). + # That works against Azure SQL Database and against LocalStack for Azure alike, because the + # emulator serves a publicly trusted certificate for the host name it returns in + # fullyQualifiedDomainName. Add TrustServerCertificate=yes only if LocalStack could not + # download that certificate (for example with SKIP_SSL_CERT_DOWNLOAD=1), in which case the + # server presents a certificate issued by the LocalStack root certificate authority. if not self.use_azure_credential: # Traditional SQL authentication From cdeebb8bc801109cfc928868307a3301987238cd Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 18 Sep 2026 12:53:42 +0200 Subject: [PATCH 2/2] Keep the stored connection string free of TrustServerCertificate too deploy.sh writes the connection string into Key Vault and the app reads it from there, so leaving the keyword in that copy would keep suggesting that validation has to be disabled, even though the app no longer sets it. Co-Authored-By: Claude Opus 5 (1M context) --- samples/web-app-sql-database/python/scripts/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/web-app-sql-database/python/scripts/deploy.sh b/samples/web-app-sql-database/python/scripts/deploy.sh index eed9ec0..58d66a5 100755 --- a/samples/web-app-sql-database/python/scripts/deploy.sh +++ b/samples/web-app-sql-database/python/scripts/deploy.sh @@ -360,7 +360,7 @@ else fi # Build connection string -SQL_CONNECTION_STRING="Server=tcp:${SQL_SERVER_FQDN},1433;Database=${SQL_DATABASE_NAME};User ID=${DATABASE_USER_NAME};Password=${DATABASE_USER_PASSWORD};Encrypt=yes;TrustServerCertificate=yes;Connection Timeout=30;" +SQL_CONNECTION_STRING="Server=tcp:${SQL_SERVER_FQDN},1433;Database=${SQL_DATABASE_NAME};User ID=${DATABASE_USER_NAME};Password=${DATABASE_USER_PASSWORD};Encrypt=yes;Connection Timeout=30;" # Create secret echo "Creating secret [$SECRET_NAME] in Key Vault..."