Connect to Azure SQL with certificate validation instead of disabling it - #122
Merged
Merged
Conversation
…sabling 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://<app>.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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
paolosalvatori
had a problem deploying
to
AZURE
September 18, 2026 10:55 — with
GitHub Actions
Failure
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Remove -C from the remaining sqlcmd calls so deployment consistently validates certificates.
Pull request overview
Updates the Python Azure SQL sample to use encrypted connections with server certificate validation.
Changes:
- Removes
TrustServerCertificate=yesfrom runtime and Key Vault connection strings. - Documents certificate validation and the LocalStack fallback.
- Retains explicit encryption.
File summaries
| File | Summary |
|---|---|
samples/web-app-sql-database/python/src/database.py |
Uses default certificate validation and documents the connection behavior. |
samples/web-app-sql-database/python/scripts/deploy.sh |
Removes the bypass from the Key Vault string, but earlier sqlcmd calls still use -C. |
Review details
Suppressed comments (1)
samples/web-app-sql-database/python/scripts/deploy.sh:363
- This changes the Key Vault connection string to validate certificates, but every
sqlcmdcall earlier in this same deployment script still uses-N -C;-Cexplicitly trusts the server certificate without validating it. The setup, schema, and seed operations therefore continue to demonstrate and rely on disabled certificate validation. Remove-C(or explicitly install/use the LocalStack CA when needed) so the deployment script consistently validates the server certificate as well.
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;"
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The sample connected to Azure SQL with
TrustServerCertificate=yes, which keeps the connection encrypted but turns certificate validation off. That was a workaround for LocalStack for Azure, where the SQL endpoint used to present a self-signed certificate that no CA chain could validate, and the sample's own comment said so: "tells the ODBC driver to accept self-signed certificates without verification".Two things make it unnecessary now. LocalStack for Azure serves a publicly trusted certificate for the host name it returns in
fullyQualifiedDomainName, so a client with default settings validates it, and Microsoft's guidance is explicit that disabling validation is the option of last resort: "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" (ODBC driver version differences).Leaving the keyword in place also taught the wrong habit: a reader copying this sample into an application would carry an adversary-in-the-middle exposure into production, for no benefit.
Fixes SMF-898
Changes
TrustServerCertificateis removed from the connection string the application builds, rather than set tono. Its default is alreadynoin ODBC Driver 18, so writing the default value only adds noise; the keyword belongs in a connection string when you deviate from the default.Encrypt=yesstays explicit, because that default does differ between driver 17 and 18.The same keyword is removed from the connection string
deploy.shstores in Key Vault, since that is the value the application reads and the one a reader is most likely to copy.The code comment now says what the absence means, and when you would still need the keyword: 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 orTrustServerCertificate=yes.Tests
The sample is otherwise unchanged and was deployed end to end on both targets.
Real Azure (
az cloud showreportingAzureCloud, invented prefix, resource group deleted afterwards):deploy.shexit 0,validate.shexit 0.https://<app>.azurewebsites.netreturned HTTP 200 with the application's own page,<title>Vacation Planner</title>, and 9 table cells rendered from the Azure SQL database.LocalStack for Azure (emulator started with
RUNTIME_COMPONENTS=azure,azlocal start-interception):deploy.shexit 0,validate.shexit 0.http://local-webapp-test.azurewebsites.azure.localhost.localstack.cloud:4566returned HTTP 200 with the same page and the same 9 cells.The first run of this check was rejected on purpose: HTTP 200 came from the App Service default welcome page while the site was still warming up, which proves nothing about the database. The runs above wait for the application's own title before asserting.
The certificate the emulator serves for a SQL host was also inspected directly:
issuer=C=US, O=Google Trust Services, CN=WR1, a public authority.🤖 Generated with Claude Code