[{"data":1,"prerenderedAt":5833},["Reactive",2],{"navigation":3,"aAII9Cz3yR":204,"tags-Azure SQL Database":397},[4,192,200],{"title":5,"_path":6,"children":7,"icon":191},"Blog","/posts",[8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,77,80,83,86,89,92,95,98,101,104,107,110,113,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,167,170,173,176,179,182,185,188],{"title":9,"_path":10},"Testing your API with REST Client","/posts/testing-your-api-with-rest-client",{"title":12,"_path":13},"HTML templating in Xamarin","/posts/html-templating-in-xamarin",{"title":15,"_path":16},"Goodbye Azure Portal, Welcome Azure CLI","/posts/welcome-azure-cli",{"title":18,"_path":19},"Coming across Gitpod","/posts/gitpod",{"title":21,"_path":22},"Handle token retrieval while querying an API","/posts/delegating-handler",{"title":24,"_path":25},"Clean up your local git branches.","/posts/cleaning-git-branches",{"title":27,"_path":28},"Automate configuration of Teams Tab SSO with PowerShell.","/posts/teams-sso-powershell",{"title":30,"_path":31},"How to do a technology watch? - Part 1","/posts/technology-watch-part1",{"title":33,"_path":34},"How to do a technology watch? - Part 2","/posts/technology-watch-part2",{"title":36,"_path":37},"You almost no longer need Key Vault references for Azure Functions.","/posts/azure-functions-custom-configuration",{"title":39,"_path":40},"How to do a technology watch? - Part 3","/posts/technology-watch-part3",{"title":42,"_path":43},"Forget DevOps, the future is already here!","/posts/devops-future",{"title":45,"_path":46},"Week 9, 2021 - Tips I learned this week","/posts/w09-2021-tips-learned-this-week",{"title":48,"_path":49},"Week 12, 2021 - Tips I learned this week","/posts/w12-2021-tips-learned-this-week",{"title":51,"_path":52},"Week 14, 2021 - Tips I learned this week","/posts/w14-2021-tips-learned-this-week",{"title":54,"_path":55},"Once upon a time in .NET","/posts/once-upon-a-time-in-dotnet",{"title":57,"_path":58},"Install your applications with winget","/posts/winget-import",{"title":60,"_path":61},"Customize your applications when installing them with winget","/posts/winget-override",{"title":63,"_path":64},"Week 22, 2021 - Tips I learned this week","/posts/w22-2021-tips-learned-this-week",{"title":66,"_path":67},"How to connect to an Azure SQL Database from C# using Azure AD","/posts/sqlclient-active-directory-authent",{"title":69,"_path":70},"Producing packages for Windows Package Manager","/posts/wingetcreate",{"title":72,"_path":73},"4 tips about GitHub Actions environment variables and contexts","/posts/github-actions-var-and-context",{"title":75,"_path":76},"AzureWebJobsStorage, the secret you don't need in your Function App.","/posts/azure-functions-without-azurewebjobsstorage",{"title":78,"_path":79},"ASP.NET Core - Lost in configuration","/posts/lost-in-configuration",{"title":81,"_path":82},"Week 39, 2021 - Tips I learned this week","/posts/w39-2021-tips-learned-this-week",{"title":84,"_path":85},"Week 41, 2021 - Tips I learned this week","/posts/w41-2021-tips-learned-this-week",{"title":87,"_path":88},"Migrating and open-sourcing my blog","/posts/migrating-blog",{"title":90,"_path":91},"Week 45, 2021 - Tips I learned this week","/posts/w45-2021-tips-learned-this-week",{"title":93,"_path":94},"Organize your GitHub stars with Astral","/posts/astral",{"title":96,"_path":97},"Pulumi with an Azure Blob Storage backend","/posts/pulumi-azure-backend",{"title":99,"_path":100},"IaC Hot Reload with Pulumi Watch","/posts/pulumi-watch",{"title":102,"_path":103},"Week 2, 2022 - Tips I learned this week","/posts/w02-2022-tips-learned-this-week",{"title":105,"_path":106},"Week 3, 2022 - Tips I learned this week","/posts/w03-2022-tips-learned-this-week",{"title":108,"_path":109},"Week 5, 2022 - Tips I learned this week","/posts/w05-2022-tips-learned-this-week",{"title":111,"_path":112},"How to provision an Azure SQL Database with Active Directory authentication","/posts/sqldatabase-active-directory-authent",{"title":114,"_path":115},"Why will I choose Pulumi over Terraform for my next project?","/posts/pulumi-vs-terraform",{"title":117,"_path":118},"Week 19, 2022 - Tips I learned this week","/posts/w19-2022-tips-learned-this-week",{"title":120,"_path":121},"Week 20, 2022 - Tips I learned this week","/posts/w20-2022-tips-learned-this-week",{"title":123,"_path":124},"Keeping secrets secure when using API Clients","/posts/http-clients-secrets",{"title":126,"_path":127},"What made me want to be a developer?","/posts/be-a-developer",{"title":129,"_path":130},"What can we do when stuck with a programming problem?","/posts/get-unstuck",{"title":132,"_path":133},"How did I automate the setup of my developer Windows laptop?","/posts/automate-developer-machine",{"title":135,"_path":136},"Discussion about API clients","/posts/http-clients",{"title":138,"_path":139},"Week 46, 2022 - Tips I learned this week","/posts/w46-2022-tips-learned-this-week",{"title":141,"_path":142},"When Pulumi met Nuke: a .NET love story","/posts/when-pulumi-met-nuke",{"title":144,"_path":145},"A year of learning and sharing - Dev Retro 2022","/posts/2022-retro",{"title":147,"_path":148},"Perform Dynamic Execution of an npm Package","/posts/pnpm-dlx",{"title":150,"_path":151},"Manage multiple Node.js versions","/posts/pnpm-env",{"title":153,"_path":154},"Introducing the Vue.js CI/CD series","/posts/vuecicd-introduction",{"title":156,"_path":157},"Execute commands using your project dependencies","/posts/pnpm-exec",{"title":159,"_path":160},"Vue.js CI/CD: Continuous Integration","/posts/vuecicd-ci",{"title":162,"_path":163},"Who is using pnpm?","/posts/pnpm-who-is-using",{"title":165,"_path":166},"Create an Azure-Ready GitHub Repository using Pulumi","/posts/azure-ready-github-repository",{"title":168,"_path":169},"Deploying to Azure from Azure DevOps without secrets","/posts/ado-workload-identity-federation",{"title":171,"_path":172},"Effortlessly Configure GitHub Repositories for Azure Deployment via OIDC","/posts/scripting-azure-ready-github-repository",{"title":174,"_path":175},"Playing with the .NET 8 Web API template","/posts/playing-with-dotnet8",{"title":177,"_path":178},"Another year of sharing and learning - Dev Retro 2023","/posts/2023-retro",{"title":180,"_path":181},"Week 4, 2024 - Tips I learned this week","/posts/w04-2024-tips-learned-this-week",{"title":183,"_path":184},"Using dependency injection with Azure .NET SDK","/posts/azure-sdk-di",{"title":186,"_path":187},"Having Fun With IT Event Calendars","/posts/it-event-calendars",{"title":189,"_path":190},"Call your Azure AD B2C protected API with authenticated HTTP requests from your JetBrains IDE","/posts/http-clients-oauth2","i-heroicons-newspaper",{"title":193,"_path":194,"children":195,"icon":199},"Goodies","/goodies",[196],{"title":197,"_path":198},"My Git Cheat Sheet","/goodies/gitcheatsheet","i-heroicons-gift-solid",{"title":201,"_path":202,"icon":203},"About","/about","i-heroicons-user-circle-solid",[205,207,209,211,214,217,220,223,226,229,231,234,237,240,242,244,247,250,253,255,258,261,264,267,270,273,276,279,282,285,287,289,292,294,297,300,303,305,308,310,313,316,319,322,325,327,329,332,335,338,341,344,347,350,353,356,359,361,363,366,369,372,375,377,380,383,385,388,391,394],[206,206],"tooling",[208,208],"vscode",[210,210],"rest",[212,213],"http","HTTP",[215,216],"razor","Razor",[218,219],"xamarin","Xamarin",[221,222],"templating","Templating",[224,225],"azure-cli","Azure CLI",[227,228],"azure","Azure",[230,230],"shell",[232,233],"github","GitHub",[235,236],"asp-net-core","ASP.NET Core",[238,239],"net",".NET",[241,241],"git",[243,243],"nushell",[245,246],"microsoft-teams","Microsoft Teams",[248,249],"powershell","PowerShell",[251,252],"azure-active-directory","Azure Active Directory",[254,254],"learning",[256,257],"azure-functions","Azure Functions",[259,260],"azure-key-vault","Azure Key Vault",[262,263],"configuration","Configuration",[265,266],"devops","DevOps",[268,269],"it","IT",[271,272],"tips-learned-this-week","tips learned this week",[274,275],"windows-terminal","Windows Terminal",[277,278],"azure-pipelines","Azure Pipelines",[280,281],"application-insights","Application Insights",[283,284],"azure-iot","Azure IoT",[286,286],"records",[288,288],"refit",[290,291],"development-box-setup","development box setup",[293,293],"winget",[295,296],"package-manager","package manager",[298,299],"azure-sql-database","Azure SQL Database",[301,302],"azure-sdk","Azure SDK",[304,304],"wingetcreate",[306,307],"github-actions","GitHub Actions",[309,309],"jq",[311,312],"pulumi","Pulumi",[314,315],"iac","IaC",[317,318],"azure-storage","Azure Storage",[320,321],"azure-signalr","Azure SignalR",[323,324],"visio","Visio",[326,326],"csharp",[328,328],"jest",[330,331],"statiq","Statiq",[333,334],"open-source","open source",[336,337],"visual-studio","Visual Studio",[339,340],"vue-js","Vue.js",[342,343],"azure-devops","Azure DevOps",[345,346],"vite","Vite",[348,349],"code-analysis","Code analysis",[351,352],"diagram","Diagram",[354,355],"terraform","Terraform",[357,358],"typescript","TypeScript",[360,360],"thoughts",[362,362],"pnpm",[364,365],"nuke","Nuke",[367,368],"pipelines","Pipelines",[370,371],"cicd","CI/CD",[373,374],"openid-connect","OpenID Connect",[376,376],"security",[378,379],"github-cli","GitHub CLI",[381,382],"microsoft-entra-id","Microsoft Entra ID",[384,384],"advent",[386,387],"finops","FinOps",[389,390],"anglesharp","AngleSharp",[392,393],"oauth2","OAuth2",[395,396],"azure-ad-b2c","Azure AD B2C",[398,3391],{"_path":112,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":111,"description":402,"lead":403,"date":404,"image":405,"badge":407,"tags":408,"body":409,"_type":3386,"_id":3387,"_source":3388,"_file":3389,"_extension":3390},"posts",false,"","In this article, we will talk about how to provision an Azure SQL Database with authentication restricted to Active Directory users/groups/applications. We will use Pulumi to do that.","Using Pulumi and its command provider to grant database permissions","2022-02-22T00:00:00.000Z",{"src":406},"/images/lockers_1.jpg",{"label":266},[252,299,228,239,312,315],{"type":410,"children":411,"toc":3368},"root",[412,419,426,451,465,475,480,486,491,804,834,840,845,1160,1172,1364,1370,1375,1388,1491,1512,1517,1522,1550,1555,1562,1576,1588,1620,1629,1645,1657,1663,1691,1696,1709,1831,1843,1875,1887,1926,1935,1962,2017,2023,2042,2048,2061,2140,2173,2178,2345,2351,2356,2538,2543,2561,2567,2586,2675,2687,2846,2867,2872,3258,3263,3296,3302,3320,3329,3335,3347,3352,3357,3362],{"type":413,"tag":414,"props":415,"children":416},"element","p",{},[417],{"type":418,"value":402},"text",{"type":413,"tag":420,"props":421,"children":423},"h2",{"id":422},"why-this-article",[424],{"type":418,"value":425},"Why this article?",{"type":413,"tag":414,"props":427,"children":428},{},[429,431,440,442,449],{"type":418,"value":430},"In ",{"type":413,"tag":432,"props":433,"children":437},"a",{"href":434,"rel":435},"https://www.techwatching.dev/posts/sqlclient-active-directory-authent",[436],"nofollow",[438],{"type":418,"value":439},"a previous article",{"type":418,"value":441},", I already talked about connecting to an Azure SQL Database using Azure Active Directory authentication. However, my focus was on querying an Azure SQL Database from C# code (from an ASP.NET 6 Minimal API that was using ",{"type":413,"tag":443,"props":444,"children":446},"code",{"className":445},[],[447],{"type":418,"value":448},"Microsoft.Data.SqlClient",{"type":418,"value":450}," 'Active Directory Default' authentication mode to be more precise), and not on the configuration of the Azure AD authentication itself.",{"type":413,"tag":414,"props":452,"children":453},{},[454,456,463],{"type":418,"value":455},"Still, in that article, I wrote an Azure CLI script that showed how to provision and configure the database with Azure AD authentication enabled. So why write another article about that? First because I did not show how to give an Azure AD entity (user, group, or managed identity) permission to access the database. (In my samples, to simplify things I was using the SQL server Azure AD administrator account to make my queries 🤫). Yet, it is something you will probably have to do if you want your App Service or Function App to query your database. Second because even if Azure CLI is great to handle Azure resources (if you are a reader of my blog, you probably know that I ",{"type":413,"tag":432,"props":457,"children":460},{"href":458,"rel":459},"https://www.techwatching.dev/posts/welcome-azure-cli",[436],[461],{"type":418,"value":462},"enjoy very much Azure CLI",{"type":418,"value":464},"), in a real project I would probably use a more advanced Infrastructure as Code solution like Pulumi. And that is what we will show here.",{"type":413,"tag":466,"props":467,"children":469},"callout",{"icon":468},"i-heroicons-chat-bubble-left-20-solid",[470],{"type":413,"tag":414,"props":471,"children":472},{},[473],{"type":418,"value":474},"If you are not familiar with Pulumi, it is an IaC solution similar to Terraform but using programming languages like C#. Speaking of C#, that is what I will use to write my infrastructure code but you can easily do the same in another language supported by Pulumi (TypeScript, Go, Python,... choose the one you are used to), the concepts stay relevant and the code will be similar.",{"type":413,"tag":414,"props":476,"children":477},{},[478],{"type":418,"value":479},"Now, let's get to the heart of the matter.",{"type":413,"tag":420,"props":481,"children":483},{"id":482},"an-azure-ad-user-as-our-sql-server-administrator",[484],{"type":418,"value":485},"An Azure AD user as our SQL Server administrator",{"type":413,"tag":414,"props":487,"children":488},{},[489],{"type":418,"value":490},"Usually, when you create an Azure SQL Server, you have to provide an administrator login and an administrator password. But I said I wanted to limit the authentication to Azure Active Directory authentication only. So we will only need an Azure AD account to set as the administrator of our SQL Server. We could use an existing Azure AD account, but let's create a new Azure AD user just for that:",{"type":413,"tag":492,"props":493,"children":496},"pre",{"className":494,"code":495,"language":326,"meta":401,"style":401},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","var config = new Config();\nvar sqlAdAdminLogin = config.Require(\"sqlAdAdmin\");\nvar sqlAdAdminPassword = config.RequireSecret(\"sqlAdPassword\");\n\nvar sqlAdAdmin = new User(\"sqlAdmin\", new UserArgs\n{\n    UserPrincipalName = sqlAdAdminLogin,\n    Password = sqlAdAdminPassword,\n    DisplayName = \"Global SQL Admin\"\n});\n",[497],{"type":413,"tag":443,"props":498,"children":499},{"__ignoreMap":401},[500,538,596,647,657,714,723,746,767,795],{"type":413,"tag":501,"props":502,"children":505},"span",{"class":503,"line":504},"line",1,[506,512,517,523,528,533],{"type":413,"tag":501,"props":507,"children":509},{"style":508},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[510],{"type":418,"value":511},"var",{"type":413,"tag":501,"props":513,"children":514},{"style":508},[515],{"type":418,"value":516}," config",{"type":413,"tag":501,"props":518,"children":520},{"style":519},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[521],{"type":418,"value":522}," =",{"type":413,"tag":501,"props":524,"children":525},{"style":519},[526],{"type":418,"value":527}," new",{"type":413,"tag":501,"props":529,"children":530},{"style":508},[531],{"type":418,"value":532}," Config",{"type":413,"tag":501,"props":534,"children":535},{"style":519},[536],{"type":418,"value":537},"();\n",{"type":413,"tag":501,"props":539,"children":541},{"class":503,"line":540},2,[542,546,551,555,560,565,571,576,581,587,591],{"type":413,"tag":501,"props":543,"children":544},{"style":508},[545],{"type":418,"value":511},{"type":413,"tag":501,"props":547,"children":548},{"style":508},[549],{"type":418,"value":550}," sqlAdAdminLogin",{"type":413,"tag":501,"props":552,"children":553},{"style":519},[554],{"type":418,"value":522},{"type":413,"tag":501,"props":556,"children":558},{"style":557},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[559],{"type":418,"value":516},{"type":413,"tag":501,"props":561,"children":562},{"style":519},[563],{"type":418,"value":564},".",{"type":413,"tag":501,"props":566,"children":568},{"style":567},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[569],{"type":418,"value":570},"Require",{"type":413,"tag":501,"props":572,"children":573},{"style":519},[574],{"type":418,"value":575},"(",{"type":413,"tag":501,"props":577,"children":578},{"style":519},[579],{"type":418,"value":580},"\"",{"type":413,"tag":501,"props":582,"children":584},{"style":583},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[585],{"type":418,"value":586},"sqlAdAdmin",{"type":413,"tag":501,"props":588,"children":589},{"style":519},[590],{"type":418,"value":580},{"type":413,"tag":501,"props":592,"children":593},{"style":519},[594],{"type":418,"value":595},");\n",{"type":413,"tag":501,"props":597,"children":599},{"class":503,"line":598},3,[600,604,609,613,617,621,626,630,634,639,643],{"type":413,"tag":501,"props":601,"children":602},{"style":508},[603],{"type":418,"value":511},{"type":413,"tag":501,"props":605,"children":606},{"style":508},[607],{"type":418,"value":608}," sqlAdAdminPassword",{"type":413,"tag":501,"props":610,"children":611},{"style":519},[612],{"type":418,"value":522},{"type":413,"tag":501,"props":614,"children":615},{"style":557},[616],{"type":418,"value":516},{"type":413,"tag":501,"props":618,"children":619},{"style":519},[620],{"type":418,"value":564},{"type":413,"tag":501,"props":622,"children":623},{"style":567},[624],{"type":418,"value":625},"RequireSecret",{"type":413,"tag":501,"props":627,"children":628},{"style":519},[629],{"type":418,"value":575},{"type":413,"tag":501,"props":631,"children":632},{"style":519},[633],{"type":418,"value":580},{"type":413,"tag":501,"props":635,"children":636},{"style":583},[637],{"type":418,"value":638},"sqlAdPassword",{"type":413,"tag":501,"props":640,"children":641},{"style":519},[642],{"type":418,"value":580},{"type":413,"tag":501,"props":644,"children":645},{"style":519},[646],{"type":418,"value":595},{"type":413,"tag":501,"props":648,"children":650},{"class":503,"line":649},4,[651],{"type":413,"tag":501,"props":652,"children":654},{"emptyLinePlaceholder":653},true,[655],{"type":418,"value":656},"\n",{"type":413,"tag":501,"props":658,"children":660},{"class":503,"line":659},5,[661,665,670,674,678,683,687,691,696,700,705,709],{"type":413,"tag":501,"props":662,"children":663},{"style":508},[664],{"type":418,"value":511},{"type":413,"tag":501,"props":666,"children":667},{"style":508},[668],{"type":418,"value":669}," sqlAdAdmin",{"type":413,"tag":501,"props":671,"children":672},{"style":519},[673],{"type":418,"value":522},{"type":413,"tag":501,"props":675,"children":676},{"style":519},[677],{"type":418,"value":527},{"type":413,"tag":501,"props":679,"children":680},{"style":508},[681],{"type":418,"value":682}," User",{"type":413,"tag":501,"props":684,"children":685},{"style":519},[686],{"type":418,"value":575},{"type":413,"tag":501,"props":688,"children":689},{"style":519},[690],{"type":418,"value":580},{"type":413,"tag":501,"props":692,"children":693},{"style":583},[694],{"type":418,"value":695},"sqlAdmin",{"type":413,"tag":501,"props":697,"children":698},{"style":519},[699],{"type":418,"value":580},{"type":413,"tag":501,"props":701,"children":702},{"style":519},[703],{"type":418,"value":704},",",{"type":413,"tag":501,"props":706,"children":707},{"style":519},[708],{"type":418,"value":527},{"type":413,"tag":501,"props":710,"children":711},{"style":508},[712],{"type":418,"value":713}," UserArgs\n",{"type":413,"tag":501,"props":715,"children":717},{"class":503,"line":716},6,[718],{"type":413,"tag":501,"props":719,"children":720},{"style":519},[721],{"type":418,"value":722},"{\n",{"type":413,"tag":501,"props":724,"children":726},{"class":503,"line":725},7,[727,732,737,741],{"type":413,"tag":501,"props":728,"children":729},{"style":557},[730],{"type":418,"value":731},"    UserPrincipalName ",{"type":413,"tag":501,"props":733,"children":734},{"style":519},[735],{"type":418,"value":736},"=",{"type":413,"tag":501,"props":738,"children":739},{"style":557},[740],{"type":418,"value":550},{"type":413,"tag":501,"props":742,"children":743},{"style":519},[744],{"type":418,"value":745},",\n",{"type":413,"tag":501,"props":747,"children":749},{"class":503,"line":748},8,[750,755,759,763],{"type":413,"tag":501,"props":751,"children":752},{"style":557},[753],{"type":418,"value":754},"    Password ",{"type":413,"tag":501,"props":756,"children":757},{"style":519},[758],{"type":418,"value":736},{"type":413,"tag":501,"props":760,"children":761},{"style":557},[762],{"type":418,"value":608},{"type":413,"tag":501,"props":764,"children":765},{"style":519},[766],{"type":418,"value":745},{"type":413,"tag":501,"props":768,"children":770},{"class":503,"line":769},9,[771,776,780,785,790],{"type":413,"tag":501,"props":772,"children":773},{"style":557},[774],{"type":418,"value":775},"    DisplayName ",{"type":413,"tag":501,"props":777,"children":778},{"style":519},[779],{"type":418,"value":736},{"type":413,"tag":501,"props":781,"children":782},{"style":519},[783],{"type":418,"value":784}," \"",{"type":413,"tag":501,"props":786,"children":787},{"style":583},[788],{"type":418,"value":789},"Global SQL Admin",{"type":413,"tag":501,"props":791,"children":792},{"style":519},[793],{"type":418,"value":794},"\"\n",{"type":413,"tag":501,"props":796,"children":798},{"class":503,"line":797},10,[799],{"type":413,"tag":501,"props":800,"children":801},{"style":519},[802],{"type":418,"value":803},"});\n",{"type":413,"tag":414,"props":805,"children":806},{},[807,809,815,817,823,825,832],{"type":418,"value":808},"To create a new Azure AD user we need a login (it will be the email of the new user in our tenant) and a password. In this example, we retrieve these values from the ",{"type":413,"tag":432,"props":810,"children":813},{"href":811,"rel":812},"https://www.pulumi.com/docs/intro/concepts/config/",[436],[814],{"type":418,"value":262},{"type":418,"value":816}," which is stored in the YAML settings file. You can notice there that we retrieve a secret (the password) from the configuration thanks to the ",{"type":413,"tag":443,"props":818,"children":820},{"className":819},[],[821],{"type":418,"value":822},"config.RequireSecret",{"type":418,"value":824}," method. Indeed to avoid exposing a secret in the configuration file or the state file, Pulumi has ",{"type":413,"tag":432,"props":826,"children":829},{"href":827,"rel":828},"https://www.pulumi.com/docs/intro/concepts/secrets/",[436],[830],{"type":418,"value":831},"built-in support for secret encryption and decryption",{"type":418,"value":833}," (not sure Terraform folks can say the same thing 😉).",{"type":413,"tag":420,"props":835,"children":837},{"id":836},"create-the-azure-sql-server-and-its-database",[838],{"type":418,"value":839},"Create the Azure SQL Server and its database.",{"type":413,"tag":414,"props":841,"children":842},{},[843],{"type":418,"value":844},"Now that we have our administrator account, we can create the Azure SQL Server:",{"type":413,"tag":492,"props":846,"children":848},{"className":494,"code":847,"language":326,"meta":401,"style":401},"var sqlServer = new Server($\"sql-sqlDbWithAzureAd-{Deployment.Instance.StackName}\", new ServerArgs\n{\n    ResourceGroupName = resourceGroup.Name,\n    Administrators = new ServerExternalAdministratorArgs\n    {\n        Login = sqlAdAdmin.UserPrincipalName,\n        Sid = sqlAdAdmin.Id,\n        AzureADOnlyAuthentication = true,\n        AdministratorType = AdministratorType.ActiveDirectory,\n        PrincipalType = PrincipalType.User,\n    },\n});\n",[849],{"type":413,"tag":443,"props":850,"children":851},{"__ignoreMap":401},[852,937,944,974,995,1003,1032,1061,1083,1113,1143,1152],{"type":413,"tag":501,"props":853,"children":854},{"class":503,"line":504},[855,859,864,868,872,877,881,886,891,896,901,905,910,914,919,924,928,932],{"type":413,"tag":501,"props":856,"children":857},{"style":508},[858],{"type":418,"value":511},{"type":413,"tag":501,"props":860,"children":861},{"style":508},[862],{"type":418,"value":863}," sqlServer",{"type":413,"tag":501,"props":865,"children":866},{"style":519},[867],{"type":418,"value":522},{"type":413,"tag":501,"props":869,"children":870},{"style":519},[871],{"type":418,"value":527},{"type":413,"tag":501,"props":873,"children":874},{"style":508},[875],{"type":418,"value":876}," Server",{"type":413,"tag":501,"props":878,"children":879},{"style":519},[880],{"type":418,"value":575},{"type":413,"tag":501,"props":882,"children":883},{"style":519},[884],{"type":418,"value":885},"$\"",{"type":413,"tag":501,"props":887,"children":888},{"style":583},[889],{"type":418,"value":890},"sql-sqlDbWithAzureAd-",{"type":413,"tag":501,"props":892,"children":893},{"style":519},[894],{"type":418,"value":895},"{",{"type":413,"tag":501,"props":897,"children":898},{"style":557},[899],{"type":418,"value":900},"Deployment",{"type":413,"tag":501,"props":902,"children":903},{"style":519},[904],{"type":418,"value":564},{"type":413,"tag":501,"props":906,"children":907},{"style":557},[908],{"type":418,"value":909},"Instance",{"type":413,"tag":501,"props":911,"children":912},{"style":519},[913],{"type":418,"value":564},{"type":413,"tag":501,"props":915,"children":916},{"style":557},[917],{"type":418,"value":918},"StackName",{"type":413,"tag":501,"props":920,"children":921},{"style":519},[922],{"type":418,"value":923},"}\"",{"type":413,"tag":501,"props":925,"children":926},{"style":519},[927],{"type":418,"value":704},{"type":413,"tag":501,"props":929,"children":930},{"style":519},[931],{"type":418,"value":527},{"type":413,"tag":501,"props":933,"children":934},{"style":508},[935],{"type":418,"value":936}," ServerArgs\n",{"type":413,"tag":501,"props":938,"children":939},{"class":503,"line":540},[940],{"type":413,"tag":501,"props":941,"children":942},{"style":519},[943],{"type":418,"value":722},{"type":413,"tag":501,"props":945,"children":946},{"class":503,"line":598},[947,952,956,961,965,970],{"type":413,"tag":501,"props":948,"children":949},{"style":557},[950],{"type":418,"value":951},"    ResourceGroupName ",{"type":413,"tag":501,"props":953,"children":954},{"style":519},[955],{"type":418,"value":736},{"type":413,"tag":501,"props":957,"children":958},{"style":557},[959],{"type":418,"value":960}," resourceGroup",{"type":413,"tag":501,"props":962,"children":963},{"style":519},[964],{"type":418,"value":564},{"type":413,"tag":501,"props":966,"children":967},{"style":557},[968],{"type":418,"value":969},"Name",{"type":413,"tag":501,"props":971,"children":972},{"style":519},[973],{"type":418,"value":745},{"type":413,"tag":501,"props":975,"children":976},{"class":503,"line":649},[977,982,986,990],{"type":413,"tag":501,"props":978,"children":979},{"style":557},[980],{"type":418,"value":981},"    Administrators ",{"type":413,"tag":501,"props":983,"children":984},{"style":519},[985],{"type":418,"value":736},{"type":413,"tag":501,"props":987,"children":988},{"style":519},[989],{"type":418,"value":527},{"type":413,"tag":501,"props":991,"children":992},{"style":508},[993],{"type":418,"value":994}," ServerExternalAdministratorArgs\n",{"type":413,"tag":501,"props":996,"children":997},{"class":503,"line":659},[998],{"type":413,"tag":501,"props":999,"children":1000},{"style":519},[1001],{"type":418,"value":1002},"    {\n",{"type":413,"tag":501,"props":1004,"children":1005},{"class":503,"line":716},[1006,1011,1015,1019,1023,1028],{"type":413,"tag":501,"props":1007,"children":1008},{"style":557},[1009],{"type":418,"value":1010},"        Login ",{"type":413,"tag":501,"props":1012,"children":1013},{"style":519},[1014],{"type":418,"value":736},{"type":413,"tag":501,"props":1016,"children":1017},{"style":557},[1018],{"type":418,"value":669},{"type":413,"tag":501,"props":1020,"children":1021},{"style":519},[1022],{"type":418,"value":564},{"type":413,"tag":501,"props":1024,"children":1025},{"style":557},[1026],{"type":418,"value":1027},"UserPrincipalName",{"type":413,"tag":501,"props":1029,"children":1030},{"style":519},[1031],{"type":418,"value":745},{"type":413,"tag":501,"props":1033,"children":1034},{"class":503,"line":725},[1035,1040,1044,1048,1052,1057],{"type":413,"tag":501,"props":1036,"children":1037},{"style":557},[1038],{"type":418,"value":1039},"        Sid ",{"type":413,"tag":501,"props":1041,"children":1042},{"style":519},[1043],{"type":418,"value":736},{"type":413,"tag":501,"props":1045,"children":1046},{"style":557},[1047],{"type":418,"value":669},{"type":413,"tag":501,"props":1049,"children":1050},{"style":519},[1051],{"type":418,"value":564},{"type":413,"tag":501,"props":1053,"children":1054},{"style":557},[1055],{"type":418,"value":1056},"Id",{"type":413,"tag":501,"props":1058,"children":1059},{"style":519},[1060],{"type":418,"value":745},{"type":413,"tag":501,"props":1062,"children":1063},{"class":503,"line":748},[1064,1069,1073,1079],{"type":413,"tag":501,"props":1065,"children":1066},{"style":557},[1067],{"type":418,"value":1068},"        AzureADOnlyAuthentication ",{"type":413,"tag":501,"props":1070,"children":1071},{"style":519},[1072],{"type":418,"value":736},{"type":413,"tag":501,"props":1074,"children":1076},{"style":1075},"--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC",[1077],{"type":418,"value":1078}," true",{"type":413,"tag":501,"props":1080,"children":1081},{"style":519},[1082],{"type":418,"value":745},{"type":413,"tag":501,"props":1084,"children":1085},{"class":503,"line":769},[1086,1091,1095,1100,1104,1109],{"type":413,"tag":501,"props":1087,"children":1088},{"style":557},[1089],{"type":418,"value":1090},"        AdministratorType ",{"type":413,"tag":501,"props":1092,"children":1093},{"style":519},[1094],{"type":418,"value":736},{"type":413,"tag":501,"props":1096,"children":1097},{"style":557},[1098],{"type":418,"value":1099}," AdministratorType",{"type":413,"tag":501,"props":1101,"children":1102},{"style":519},[1103],{"type":418,"value":564},{"type":413,"tag":501,"props":1105,"children":1106},{"style":557},[1107],{"type":418,"value":1108},"ActiveDirectory",{"type":413,"tag":501,"props":1110,"children":1111},{"style":519},[1112],{"type":418,"value":745},{"type":413,"tag":501,"props":1114,"children":1115},{"class":503,"line":797},[1116,1121,1125,1130,1134,1139],{"type":413,"tag":501,"props":1117,"children":1118},{"style":557},[1119],{"type":418,"value":1120},"        PrincipalType ",{"type":413,"tag":501,"props":1122,"children":1123},{"style":519},[1124],{"type":418,"value":736},{"type":413,"tag":501,"props":1126,"children":1127},{"style":557},[1128],{"type":418,"value":1129}," PrincipalType",{"type":413,"tag":501,"props":1131,"children":1132},{"style":519},[1133],{"type":418,"value":564},{"type":413,"tag":501,"props":1135,"children":1136},{"style":557},[1137],{"type":418,"value":1138},"User",{"type":413,"tag":501,"props":1140,"children":1141},{"style":519},[1142],{"type":418,"value":745},{"type":413,"tag":501,"props":1144,"children":1146},{"class":503,"line":1145},11,[1147],{"type":413,"tag":501,"props":1148,"children":1149},{"style":519},[1150],{"type":418,"value":1151},"    },\n",{"type":413,"tag":501,"props":1153,"children":1155},{"class":503,"line":1154},12,[1156],{"type":413,"tag":501,"props":1157,"children":1158},{"style":519},[1159],{"type":418,"value":803},{"type":413,"tag":414,"props":1161,"children":1162},{},[1163,1165,1170],{"type":418,"value":1164},"Nothing special here: we are using the variable ",{"type":413,"tag":443,"props":1166,"children":1168},{"className":1167},[],[1169],{"type":418,"value":695},{"type":418,"value":1171}," that is our newly created user to set the administrator of the SQL Server and we set the authentication to Azure AD only. We can then create the database:",{"type":413,"tag":492,"props":1173,"children":1175},{"className":494,"code":1174,"language":326,"meta":401,"style":401},"var database = new Database(\"sqldb-sqlDbWithAzureAd-Main\", new DatabaseArgs\n{\n    ResourceGroupName = resourceGroup.Name,\n    ServerName = sqlServer.Name,\n    Sku = new SkuArgs\n    {\n        Name = \"Basic\"\n    }\n});\n",[1176],{"type":413,"tag":443,"props":1177,"children":1178},{"__ignoreMap":401},[1179,1234,1241,1268,1296,1317,1324,1349,1357],{"type":413,"tag":501,"props":1180,"children":1181},{"class":503,"line":504},[1182,1186,1191,1195,1199,1204,1208,1212,1217,1221,1225,1229],{"type":413,"tag":501,"props":1183,"children":1184},{"style":508},[1185],{"type":418,"value":511},{"type":413,"tag":501,"props":1187,"children":1188},{"style":508},[1189],{"type":418,"value":1190}," database",{"type":413,"tag":501,"props":1192,"children":1193},{"style":519},[1194],{"type":418,"value":522},{"type":413,"tag":501,"props":1196,"children":1197},{"style":519},[1198],{"type":418,"value":527},{"type":413,"tag":501,"props":1200,"children":1201},{"style":508},[1202],{"type":418,"value":1203}," Database",{"type":413,"tag":501,"props":1205,"children":1206},{"style":519},[1207],{"type":418,"value":575},{"type":413,"tag":501,"props":1209,"children":1210},{"style":519},[1211],{"type":418,"value":580},{"type":413,"tag":501,"props":1213,"children":1214},{"style":583},[1215],{"type":418,"value":1216},"sqldb-sqlDbWithAzureAd-Main",{"type":413,"tag":501,"props":1218,"children":1219},{"style":519},[1220],{"type":418,"value":580},{"type":413,"tag":501,"props":1222,"children":1223},{"style":519},[1224],{"type":418,"value":704},{"type":413,"tag":501,"props":1226,"children":1227},{"style":519},[1228],{"type":418,"value":527},{"type":413,"tag":501,"props":1230,"children":1231},{"style":508},[1232],{"type":418,"value":1233}," DatabaseArgs\n",{"type":413,"tag":501,"props":1235,"children":1236},{"class":503,"line":540},[1237],{"type":413,"tag":501,"props":1238,"children":1239},{"style":519},[1240],{"type":418,"value":722},{"type":413,"tag":501,"props":1242,"children":1243},{"class":503,"line":598},[1244,1248,1252,1256,1260,1264],{"type":413,"tag":501,"props":1245,"children":1246},{"style":557},[1247],{"type":418,"value":951},{"type":413,"tag":501,"props":1249,"children":1250},{"style":519},[1251],{"type":418,"value":736},{"type":413,"tag":501,"props":1253,"children":1254},{"style":557},[1255],{"type":418,"value":960},{"type":413,"tag":501,"props":1257,"children":1258},{"style":519},[1259],{"type":418,"value":564},{"type":413,"tag":501,"props":1261,"children":1262},{"style":557},[1263],{"type":418,"value":969},{"type":413,"tag":501,"props":1265,"children":1266},{"style":519},[1267],{"type":418,"value":745},{"type":413,"tag":501,"props":1269,"children":1270},{"class":503,"line":649},[1271,1276,1280,1284,1288,1292],{"type":413,"tag":501,"props":1272,"children":1273},{"style":557},[1274],{"type":418,"value":1275},"    ServerName ",{"type":413,"tag":501,"props":1277,"children":1278},{"style":519},[1279],{"type":418,"value":736},{"type":413,"tag":501,"props":1281,"children":1282},{"style":557},[1283],{"type":418,"value":863},{"type":413,"tag":501,"props":1285,"children":1286},{"style":519},[1287],{"type":418,"value":564},{"type":413,"tag":501,"props":1289,"children":1290},{"style":557},[1291],{"type":418,"value":969},{"type":413,"tag":501,"props":1293,"children":1294},{"style":519},[1295],{"type":418,"value":745},{"type":413,"tag":501,"props":1297,"children":1298},{"class":503,"line":659},[1299,1304,1308,1312],{"type":413,"tag":501,"props":1300,"children":1301},{"style":557},[1302],{"type":418,"value":1303},"    Sku ",{"type":413,"tag":501,"props":1305,"children":1306},{"style":519},[1307],{"type":418,"value":736},{"type":413,"tag":501,"props":1309,"children":1310},{"style":519},[1311],{"type":418,"value":527},{"type":413,"tag":501,"props":1313,"children":1314},{"style":508},[1315],{"type":418,"value":1316}," SkuArgs\n",{"type":413,"tag":501,"props":1318,"children":1319},{"class":503,"line":716},[1320],{"type":413,"tag":501,"props":1321,"children":1322},{"style":519},[1323],{"type":418,"value":1002},{"type":413,"tag":501,"props":1325,"children":1326},{"class":503,"line":725},[1327,1332,1336,1340,1345],{"type":413,"tag":501,"props":1328,"children":1329},{"style":557},[1330],{"type":418,"value":1331},"        Name ",{"type":413,"tag":501,"props":1333,"children":1334},{"style":519},[1335],{"type":418,"value":736},{"type":413,"tag":501,"props":1337,"children":1338},{"style":519},[1339],{"type":418,"value":784},{"type":413,"tag":501,"props":1341,"children":1342},{"style":583},[1343],{"type":418,"value":1344},"Basic",{"type":413,"tag":501,"props":1346,"children":1347},{"style":519},[1348],{"type":418,"value":794},{"type":413,"tag":501,"props":1350,"children":1351},{"class":503,"line":748},[1352],{"type":413,"tag":501,"props":1353,"children":1354},{"style":519},[1355],{"type":418,"value":1356},"    }\n",{"type":413,"tag":501,"props":1358,"children":1359},{"class":503,"line":769},[1360],{"type":413,"tag":501,"props":1361,"children":1362},{"style":519},[1363],{"type":418,"value":803},{"type":413,"tag":420,"props":1365,"children":1367},{"id":1366},"grant-sql-database-access-permissions-to-azure-ad-entities",[1368],{"type":418,"value":1369},"Grant SQL Database access permissions to Azure AD entities",{"type":413,"tag":414,"props":1371,"children":1372},{},[1373],{"type":418,"value":1374},"Once we have provisioned the Azure SQL Server and its database, here comes the tough part: we need to configure who can access the database. In a project, you will probably have to give access to some users and to the Azure resources that need to query the database (you will have to assign these resources a managed identity before that). But to keep things simple, we will just consider we need to grant SQL Database access to an Azure AD group. That could be a good way to do things by the way: create an Azure AD group, grant permissions to this group and add users and managed identities that need access to the database.",{"type":413,"tag":414,"props":1376,"children":1377},{},[1378,1380,1387],{"type":418,"value":1379},"Why did I say that this part was tough? It's because to grant SQL database permissions, we need to execute an SQL command on the Server as you can read ",{"type":413,"tag":432,"props":1381,"children":1384},{"href":1382,"rel":1383},"https://docs.microsoft.com/en-us/azure/app-service/tutorial-connect-msi-sql-database?tabs=windowsclient%2Cef%2Cdotnet#grant-permissions-to-managed-identity",[436],[1385],{"type":418,"value":1386},"in the documentation",{"type":418,"value":564},{"type":413,"tag":492,"props":1389,"children":1393},{"className":1390,"code":1391,"language":1392,"meta":401,"style":401},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CREATE USER [\u003Cidentity-name>] FROM EXTERNAL PROVIDER;\nALTER ROLE db_datareader ADD MEMBER [\u003Cidentity-name>];\nALTER ROLE db_datawriter ADD MEMBER [\u003Cidentity-name>];\nGO\n","sql",[1394],{"type":413,"tag":443,"props":1395,"children":1396},{"__ignoreMap":401},[1397,1431,1459,1483],{"type":413,"tag":501,"props":1398,"children":1399},{"class":503,"line":504},[1400,1406,1411,1416,1421,1426],{"type":413,"tag":501,"props":1401,"children":1403},{"style":1402},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[1404],{"type":418,"value":1405},"CREATE",{"type":413,"tag":501,"props":1407,"children":1408},{"style":557},[1409],{"type":418,"value":1410}," USER [\u003Cidentity-name>] ",{"type":413,"tag":501,"props":1412,"children":1413},{"style":1402},[1414],{"type":418,"value":1415},"FROM",{"type":413,"tag":501,"props":1417,"children":1418},{"style":1402},[1419],{"type":418,"value":1420}," EXTERNAL",{"type":413,"tag":501,"props":1422,"children":1423},{"style":1402},[1424],{"type":418,"value":1425}," PROVIDER",{"type":413,"tag":501,"props":1427,"children":1428},{"style":557},[1429],{"type":418,"value":1430},";\n",{"type":413,"tag":501,"props":1432,"children":1433},{"class":503,"line":540},[1434,1439,1444,1449,1454],{"type":413,"tag":501,"props":1435,"children":1436},{"style":1402},[1437],{"type":418,"value":1438},"ALTER",{"type":413,"tag":501,"props":1440,"children":1441},{"style":1402},[1442],{"type":418,"value":1443}," ROLE",{"type":413,"tag":501,"props":1445,"children":1446},{"style":557},[1447],{"type":418,"value":1448}," db_datareader ",{"type":413,"tag":501,"props":1450,"children":1451},{"style":1402},[1452],{"type":418,"value":1453},"ADD",{"type":413,"tag":501,"props":1455,"children":1456},{"style":557},[1457],{"type":418,"value":1458}," MEMBER [\u003Cidentity-name>];\n",{"type":413,"tag":501,"props":1460,"children":1461},{"class":503,"line":598},[1462,1466,1470,1475,1479],{"type":413,"tag":501,"props":1463,"children":1464},{"style":1402},[1465],{"type":418,"value":1438},{"type":413,"tag":501,"props":1467,"children":1468},{"style":1402},[1469],{"type":418,"value":1443},{"type":413,"tag":501,"props":1471,"children":1472},{"style":557},[1473],{"type":418,"value":1474}," db_datawriter ",{"type":413,"tag":501,"props":1476,"children":1477},{"style":1402},[1478],{"type":418,"value":1453},{"type":413,"tag":501,"props":1480,"children":1481},{"style":557},[1482],{"type":418,"value":1458},{"type":413,"tag":501,"props":1484,"children":1485},{"class":503,"line":649},[1486],{"type":413,"tag":501,"props":1487,"children":1488},{"style":1402},[1489],{"type":418,"value":1490},"GO\n",{"type":413,"tag":414,"props":1492,"children":1493},{},[1494,1496,1502,1504,1510],{"type":418,"value":1495},"With this command, we are creating a user and giving ",{"type":413,"tag":443,"props":1497,"children":1499},{"className":1498},[],[1500],{"type":418,"value":1501},"db_datareader",{"type":418,"value":1503}," and ",{"type":413,"tag":443,"props":1505,"children":1507},{"className":1506},[],[1508],{"type":418,"value":1509},"db_datawriter",{"type":418,"value":1511}," roles. However it is not a classical user, it's a user that is \"external\" to the database: in our case, it corresponds to an Azure AD entity (a user, group, or application).",{"type":413,"tag":414,"props":1513,"children":1514},{},[1515],{"type":418,"value":1516},"So it's not just about setting a property to properly configure an Azure resource, it's a bit more complicated.",{"type":413,"tag":414,"props":1518,"children":1519},{},[1520],{"type":418,"value":1521},"I see multiple ways of doing that:",{"type":413,"tag":1523,"props":1524,"children":1525},"ul",{},[1526,1532,1537],{"type":413,"tag":1527,"props":1528,"children":1529},"li",{},[1530],{"type":418,"value":1531},"Create a new Pulumi provider \"SQL Server provider\" that is to able manage users in an SQL Server database",{"type":413,"tag":1527,"props":1533,"children":1534},{},[1535],{"type":418,"value":1536},"Write custom C# code that executes the SQL command once the database is created",{"type":413,"tag":1527,"props":1538,"children":1539},{},[1540,1542,1548],{"type":418,"value":1541},"Use the Pulumi Command provider to execute the SQL command using the ",{"type":413,"tag":443,"props":1543,"children":1545},{"className":1544},[],[1546],{"type":418,"value":1547},"sqlcmd",{"type":418,"value":1549}," utility",{"type":413,"tag":414,"props":1551,"children":1552},{},[1553],{"type":418,"value":1554},"Let's review these solutions.",{"type":413,"tag":1556,"props":1557,"children":1559},"h3",{"id":1558},"new-sql-server-provider",[1560],{"type":418,"value":1561},"New \"SQL Server Provider\"",{"type":413,"tag":414,"props":1563,"children":1564},{},[1565,1567,1574],{"type":418,"value":1566},"To manage SQL Server resources like users and roles, we can create a complete provider. We could create it from scratch of course or use this ",{"type":413,"tag":432,"props":1568,"children":1571},{"href":1569,"rel":1570},"https://github.com/pulumi/pulumi-provider-boilerplate",[436],[1572],{"type":418,"value":1573},"Pulumi GitHub repository",{"type":418,"value":1575}," that provides some boilerplate code to create a Pulumi provider. Usually, Pulumi providers are written in Go (like the Terraform providers by the way) and generate SDKs for all programming languages supported by Pulumi.",{"type":413,"tag":414,"props":1577,"children":1578},{},[1579],{"type":413,"tag":1580,"props":1581,"children":1587},"img",{"alt":1582,"className":1583,"src":1586},"xyz Pulumi Provider boilerplate code repository on GitHub.",[1584,1585],"rounded-lg","mx-auto","/posts/images/sqldatabase_ad_provider_1.png",[],{"type":413,"tag":414,"props":1589,"children":1590},{},[1591,1593,1600,1602,1609,1611,1618],{"type":418,"value":1592},"Another way would be to adapt the existing ",{"type":413,"tag":432,"props":1594,"children":1597},{"href":1595,"rel":1596},"https://registry.terraform.io/providers/betr-io/mssql/latest/docs",[436],[1598],{"type":418,"value":1599},"Microsoft SQL Server Provider",{"type":418,"value":1601}," for Terraform. This Terraform provider made by the community enables you to create and manage logins and users on a SQL Server. I talked about \"adapting\" this provider because you can create a Pulumi provider out of a Terraform provider by using the ",{"type":413,"tag":432,"props":1603,"children":1606},{"href":1604,"rel":1605},"https://github.com/pulumi/pulumi-terraform-bridge",[436],[1607],{"type":418,"value":1608},"Pulumi Terraform Bridge",{"type":418,"value":1610},". That's great because instead of reinventing the wheel you can benefit from Terraform ecosystem by creating a Pulumi provider that wraps an existing Terraform provider. This ",{"type":413,"tag":432,"props":1612,"children":1615},{"href":1613,"rel":1614},"https://github.com/pulumi/pulumi-tf-provider-boilerplate",[436],[1616],{"type":418,"value":1617},"GitHub repository",{"type":418,"value":1619}," contains boilerplate code to do exactly that.",{"type":413,"tag":414,"props":1621,"children":1622},{},[1623],{"type":413,"tag":1580,"props":1624,"children":1628},{"alt":1625,"className":1626,"src":1627},"Pulumi Terraform Bridge repository on GitHub.",[1584,1585],"/posts/images/sqldatabase_ad_provider_2.png",[],{"type":413,"tag":466,"props":1630,"children":1631},{"icon":468},[1632],{"type":413,"tag":414,"props":1633,"children":1634},{},[1635,1637,1643],{"type":418,"value":1636},"You might have noticed that I sometimes criticize Terraform in my articles. That's not because I think Terraform is a bad infrastructure as code solution, in fact, I think it is a great solution with a rich ecosystem. However, I am critical of Terraform because I believe Infrastructure as Code should be done with programming languages instead of Domain-Specific Languages. Moreover, there are some areas (API coverage of major cloud providers, security, IDE support, ...) where I found Terraform is not good enough, especially compared to other platforms like Pulumi. So I am always a bit disappointed when I see that many people choose by default Terraform as their infrastructure as code platform without considering alternatives (and I am not only talking about Pulumi, there are also Farmer and Bicep for instance), even when these alternatives would be better suited to their use cases. That being said, Terraform has also advantages like its great community that creates and contributes to many providers like the ",{"type":413,"tag":443,"props":1638,"children":1640},{"className":1639},[],[1641],{"type":418,"value":1642},"mssql",{"type":418,"value":1644}," one.",{"type":413,"tag":414,"props":1646,"children":1647},{},[1648,1650,1655],{"type":418,"value":1649},"This first solution of creating a new \"SQL Server Provider\" (whether it be from scratch, from boilerplate code, or from the ",{"type":413,"tag":443,"props":1651,"children":1653},{"className":1652},[],[1654],{"type":418,"value":1642},{"type":418,"value":1656}," Terraform provider) is interesting but could be time-consuming because there are some things to set up and some amount of code to write.",{"type":413,"tag":1556,"props":1658,"children":1660},{"id":1659},"custom-c-code",[1661],{"type":418,"value":1662},"Custom C# code",{"type":413,"tag":414,"props":1664,"children":1665},{},[1666,1668,1680,1682,1689],{"type":418,"value":1667},"When you need to do something specific and there is no existing provider that can help you with it, you can just write the code to do it yourself without creating a complete provider. It's one of the reasons why I like Pulumi, even if you are doing Infrastructure as Code, at the end of the day you are just developing software so you can code what you need in the language you are familiar with. For instance, as I am developing in .NET, I can use the ",{"type":413,"tag":432,"props":1669,"children":1672},{"href":1670,"rel":1671},"https://docs.microsoft.com/en-us/sql/connect/ado-net/overview-sqlclient-driver",[436],[1673,1678],{"type":413,"tag":443,"props":1674,"children":1676},{"className":1675},[],[1677],{"type":418,"value":448},{"type":418,"value":1679}," library",{"type":418,"value":1681}," (which is a data provider for Azure SQL Database) to connect and send commands to the database. And if I want to use ",{"type":413,"tag":432,"props":1683,"children":1686},{"href":1684,"rel":1685},"https://github.com/DapperLib/Dapper",[436],[1687],{"type":418,"value":1688},"Dapper",{"type":418,"value":1690}," on top of it because that's the library I am used to for querying a database I can. Hence writing the code that executes on the database the SQL command we have previously seen should not be very difficult.",{"type":413,"tag":414,"props":1692,"children":1693},{},[1694],{"type":418,"value":1695},"Now, even if we are using imperative language in Pulumi to write the infrastructure code it's still declarative infrastructure as code with a state. Therefore, we have to be careful about how and when this custom code should be executed.",{"type":413,"tag":414,"props":1697,"children":1698},{},[1699,1701,1707],{"type":418,"value":1700},"The easiest way is to use an ",{"type":413,"tag":443,"props":1702,"children":1704},{"className":1703},[],[1705],{"type":418,"value":1706},"Apply",{"type":418,"value":1708}," method on an output of the database like this:",{"type":413,"tag":492,"props":1710,"children":1712},{"className":494,"code":1711,"language":326,"meta":401,"style":401},"database.Name.Apply(name =>\n{\n    /*** \n     * Indempotent code using Microsoft.Data.SqlClient library\n     * to execute the SQL command that assigns the correct roles\n     * to the Azure AD group we want to have access to the database.\n    ***/ \n    return true;\n});\n",[1713],{"type":413,"tag":443,"props":1714,"children":1715},{"__ignoreMap":401},[1716,1754,1761,1770,1778,1786,1794,1807,1824],{"type":413,"tag":501,"props":1717,"children":1718},{"class":503,"line":504},[1719,1724,1728,1732,1736,1740,1744,1749],{"type":413,"tag":501,"props":1720,"children":1721},{"style":557},[1722],{"type":418,"value":1723},"database",{"type":413,"tag":501,"props":1725,"children":1726},{"style":519},[1727],{"type":418,"value":564},{"type":413,"tag":501,"props":1729,"children":1730},{"style":557},[1731],{"type":418,"value":969},{"type":413,"tag":501,"props":1733,"children":1734},{"style":519},[1735],{"type":418,"value":564},{"type":413,"tag":501,"props":1737,"children":1738},{"style":567},[1739],{"type":418,"value":1706},{"type":413,"tag":501,"props":1741,"children":1742},{"style":519},[1743],{"type":418,"value":575},{"type":413,"tag":501,"props":1745,"children":1746},{"style":508},[1747],{"type":418,"value":1748},"name",{"type":413,"tag":501,"props":1750,"children":1751},{"style":519},[1752],{"type":418,"value":1753}," =>\n",{"type":413,"tag":501,"props":1755,"children":1756},{"class":503,"line":540},[1757],{"type":413,"tag":501,"props":1758,"children":1759},{"style":519},[1760],{"type":418,"value":722},{"type":413,"tag":501,"props":1762,"children":1763},{"class":503,"line":598},[1764],{"type":413,"tag":501,"props":1765,"children":1767},{"style":1766},"--shiki-light:#90A4AE;--shiki-default:#546E7A;--shiki-dark:#676E95;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[1768],{"type":418,"value":1769},"    /*** \n",{"type":413,"tag":501,"props":1771,"children":1772},{"class":503,"line":649},[1773],{"type":413,"tag":501,"props":1774,"children":1775},{"style":1766},[1776],{"type":418,"value":1777},"     * Indempotent code using Microsoft.Data.SqlClient library\n",{"type":413,"tag":501,"props":1779,"children":1780},{"class":503,"line":659},[1781],{"type":413,"tag":501,"props":1782,"children":1783},{"style":1766},[1784],{"type":418,"value":1785},"     * to execute the SQL command that assigns the correct roles\n",{"type":413,"tag":501,"props":1787,"children":1788},{"class":503,"line":716},[1789],{"type":413,"tag":501,"props":1790,"children":1791},{"style":1766},[1792],{"type":418,"value":1793},"     * to the Azure AD group we want to have access to the database.\n",{"type":413,"tag":501,"props":1795,"children":1796},{"class":503,"line":725},[1797,1802],{"type":413,"tag":501,"props":1798,"children":1799},{"style":1766},[1800],{"type":418,"value":1801},"    ***/",{"type":413,"tag":501,"props":1803,"children":1804},{"style":557},[1805],{"type":418,"value":1806}," \n",{"type":413,"tag":501,"props":1808,"children":1809},{"class":503,"line":748},[1810,1816,1820],{"type":413,"tag":501,"props":1811,"children":1813},{"style":1812},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[1814],{"type":418,"value":1815},"    return",{"type":413,"tag":501,"props":1817,"children":1818},{"style":1075},[1819],{"type":418,"value":1078},{"type":413,"tag":501,"props":1821,"children":1822},{"style":519},[1823],{"type":418,"value":1430},{"type":413,"tag":501,"props":1825,"children":1826},{"class":503,"line":769},[1827],{"type":413,"tag":501,"props":1828,"children":1829},{"style":519},[1830],{"type":418,"value":803},{"type":413,"tag":414,"props":1832,"children":1833},{},[1834,1836,1841],{"type":418,"value":1835},"The code in the ",{"type":413,"tag":443,"props":1837,"children":1839},{"className":1838},[],[1840],{"type":418,"value":1706},{"type":418,"value":1842}," will execute on every run after the resource is created, that is why it needs to be idempotent. Having to make the code idempotent is a constraint that I would prefer to avoid but at least it gives us a simple way to execute the code that grants access to the database.",{"type":413,"tag":414,"props":1844,"children":1845},{},[1846,1848,1855,1857,1864,1866,1873],{"type":418,"value":1847},"Another way would be to use ",{"type":413,"tag":432,"props":1849,"children":1852},{"href":1850,"rel":1851},"https://www.pulumi.com/docs/intro/concepts/resources/dynamic-providers/",[436],[1853],{"type":418,"value":1854},"Dynamic Providers",{"type":418,"value":1856}," whose purpose is exactly that: do an infrastructure task that no existing provider can help you deliver. You can see some use cases of dynamic providers in ",{"type":413,"tag":432,"props":1858,"children":1861},{"href":1859,"rel":1860},"https://www.pulumi.com/blog/dynamic-providers/#sample-use-cases",[436],[1862],{"type":418,"value":1863},"this Pulumi article",{"type":418,"value":1865},". In our use case, we could imagine writing a dynamic resource provider for an Azure AD entity user in an Azure SQL Database.  We would have to implement the different CRUD operations to handle the different use cases properly (a user is added, a user is removed, user roles are updated, ...). Unfortunately, as you can see in ",{"type":413,"tag":432,"props":1867,"children":1870},{"href":1868,"rel":1869},"https://github.com/pulumi/pulumi/issues/3638",[436],[1871],{"type":418,"value":1872},"this GitHub issue",{"type":418,"value":1874},", .NET Dynamic Providers are not yet supported (only TypesScript, JavaScript and Python are for the moment). It's a shame because Dynamic Providers provide an easy and efficient way of supporting custom resource types.",{"type":413,"tag":1556,"props":1876,"children":1878},{"id":1877},"command-provider-with-the-sqlcmd-utility",[1879,1881,1886],{"type":418,"value":1880},"Command provider with the ",{"type":413,"tag":443,"props":1882,"children":1884},{"className":1883},[],[1885],{"type":418,"value":1547},{"type":418,"value":1549},{"type":413,"tag":414,"props":1888,"children":1889},{},[1890,1896,1898,1909,1911,1916,1918,1925],{"type":413,"tag":432,"props":1891,"children":1893},{"href":1382,"rel":1892},[436],[1894],{"type":418,"value":1895},"The Microsoft tutorial",{"type":418,"value":1897},", that shows how to grant database permissions to an Azure AD entity, explains how the necessary SQL commands can be run using the ",{"type":413,"tag":432,"props":1899,"children":1902},{"href":1900,"rel":1901},"https://docs.microsoft.com/en-us/sql/tools/sqlcmd-utility",[436],[1903,1908],{"type":413,"tag":443,"props":1904,"children":1906},{"className":1905},[],[1907],{"type":418,"value":1547},{"type":418,"value":1549},{"type":418,"value":1910},". So instead of writing some C# code to do the same, an interesting idea would be to directly run the ",{"type":413,"tag":443,"props":1912,"children":1914},{"className":1913},[],[1915],{"type":418,"value":1547},{"type":418,"value":1917}," utility. And you know what? There is a Pulumi provider for executing commands and scripts: ",{"type":413,"tag":432,"props":1919,"children":1922},{"href":1920,"rel":1921},"https://www.pulumi.com/registry/packages/command/api-docs/",[436],[1923],{"type":418,"value":1924},"the Command Provider",{"type":418,"value":564},{"type":413,"tag":414,"props":1927,"children":1928},{},[1929],{"type":413,"tag":1580,"props":1930,"children":1934},{"alt":1931,"className":1932,"src":1933},"Pulumi Command Provider on GitHub.",[1584,1585],"/posts/images/sqldatabase_ad_pulumi_1.png",[],{"type":413,"tag":414,"props":1936,"children":1937},{},[1938,1940,1945,1947,1953,1955,1960],{"type":418,"value":1939},"Because it's a Pulumi provider, the ",{"type":413,"tag":443,"props":1941,"children":1943},{"className":1942},[],[1944],{"type":418,"value":1547},{"type":418,"value":1946}," command would be executed \"as part of the Pulumi resource model\" which means the scripts would be executed at the corresponding time of the resource life-cycle (the ",{"type":413,"tag":443,"props":1948,"children":1950},{"className":1949},[],[1951],{"type":418,"value":1952},"create",{"type":418,"value":1954}," script when the resource is created and so on). So it's very nice and not the same as executing the ",{"type":413,"tag":443,"props":1956,"children":1958},{"className":1957},[],[1959],{"type":418,"value":1547},{"type":418,"value":1961}," outside of a Pulumi program, without access to all the variables and where you would have to make your script idempotent. Moreover, the ability to execute commands remotely can bring interesting use cases, just not for our current concern here.",{"type":413,"tag":466,"props":1963,"children":1965},{"icon":1964},"i-heroicons-light-bulb",[1966],{"type":413,"tag":414,"props":1967,"children":1968},{},[1969,1971,1976,1977,1983,1985,1991,1993,1999,2000,2006,2008,2015],{"type":418,"value":1970},"Pulumi Command Provider is currently in preview and only supports running scripts on ",{"type":413,"tag":443,"props":1972,"children":1974},{"className":1973},[],[1975],{"type":418,"value":1952},{"type":418,"value":1503},{"type":413,"tag":443,"props":1978,"children":1980},{"className":1979},[],[1981],{"type":418,"value":1982},"destroy",{"type":418,"value":1984}," operations (support for ",{"type":413,"tag":443,"props":1986,"children":1988},{"className":1987},[],[1989],{"type":418,"value":1990},"diff",{"type":418,"value":1992},", ",{"type":413,"tag":443,"props":1994,"children":1996},{"className":1995},[],[1997],{"type":418,"value":1998},"update",{"type":418,"value":1503},{"type":413,"tag":443,"props":2001,"children":2003},{"className":2002},[],[2004],{"type":418,"value":2005},"read",{"type":418,"value":2007}," operations ",{"type":413,"tag":432,"props":2009,"children":2012},{"href":2010,"rel":2011},"https://github.com/pulumi/pulumi-command/issues/20",[436],[2013],{"type":418,"value":2014},"will probably be added later",{"type":418,"value":2016},"). It works fine but does not log details about the error when a script fails, which makes debugging difficult. That should not prevent you from using it but as with any components in preview, use it with caution knowing everything is not perfect yet.",{"type":413,"tag":420,"props":2018,"children":2020},{"id":2019},"implement-the-database-permissions-for-an-azure-ad-group",[2021],{"type":418,"value":2022},"Implement the database permissions for an Azure AD Group",{"type":413,"tag":414,"props":2024,"children":2025},{},[2026,2028,2033,2035,2040],{"type":418,"value":2027},"Of the 3 possible solutions let's take the 3rd one with the Command provider and the ",{"type":413,"tag":443,"props":2029,"children":2031},{"className":2030},[],[2032],{"type":418,"value":1547},{"type":418,"value":2034}," utility. It is probably not the \"best\" solution but I thought it would be simpler to use the ",{"type":413,"tag":443,"props":2036,"children":2038},{"className":2037},[],[2039],{"type":418,"value":1547},{"type":418,"value":2041}," utility than writing a complete provider or even custom C# code to do the same. Furthermore, it's the opportunity to test the Command provider which is fairly new.",{"type":413,"tag":1556,"props":2043,"children":2045},{"id":2044},"allow-the-machine-running-the-pulumi-program-to-connect-to-the-sql-server",[2046],{"type":418,"value":2047},"Allow the machine running the Pulumi program to connect to the SQL Server",{"type":413,"tag":414,"props":2049,"children":2050},{},[2051,2053,2059],{"type":418,"value":2052},"To run a SQL command in the database, the machine that executes the Pulumi program needs to have its public IP authorized. To programmatically retrieve the public IP address from where the Pulumi program is running we can use ",{"type":413,"tag":443,"props":2054,"children":2056},{"className":2055},[],[2057],{"type":418,"value":2058},"ipify API",{"type":418,"value":2060},". It's a simple open source HTTP API that returns the public IP address of the caller.",{"type":413,"tag":492,"props":2062,"children":2064},{"className":494,"code":2063,"language":326,"meta":401,"style":401},"var publicIp = Output.Create(new HttpClient().GetStringAsync(\"https://api.ipify.org\"));\n",[2065],{"type":413,"tag":443,"props":2066,"children":2067},{"__ignoreMap":401},[2068],{"type":413,"tag":501,"props":2069,"children":2070},{"class":503,"line":504},[2071,2075,2080,2084,2089,2093,2098,2103,2108,2113,2118,2122,2126,2131,2135],{"type":413,"tag":501,"props":2072,"children":2073},{"style":508},[2074],{"type":418,"value":511},{"type":413,"tag":501,"props":2076,"children":2077},{"style":508},[2078],{"type":418,"value":2079}," publicIp",{"type":413,"tag":501,"props":2081,"children":2082},{"style":519},[2083],{"type":418,"value":522},{"type":413,"tag":501,"props":2085,"children":2086},{"style":557},[2087],{"type":418,"value":2088}," Output",{"type":413,"tag":501,"props":2090,"children":2091},{"style":519},[2092],{"type":418,"value":564},{"type":413,"tag":501,"props":2094,"children":2095},{"style":567},[2096],{"type":418,"value":2097},"Create",{"type":413,"tag":501,"props":2099,"children":2100},{"style":519},[2101],{"type":418,"value":2102},"(new",{"type":413,"tag":501,"props":2104,"children":2105},{"style":508},[2106],{"type":418,"value":2107}," HttpClient",{"type":413,"tag":501,"props":2109,"children":2110},{"style":519},[2111],{"type":418,"value":2112},"().",{"type":413,"tag":501,"props":2114,"children":2115},{"style":567},[2116],{"type":418,"value":2117},"GetStringAsync",{"type":413,"tag":501,"props":2119,"children":2120},{"style":519},[2121],{"type":418,"value":575},{"type":413,"tag":501,"props":2123,"children":2124},{"style":519},[2125],{"type":418,"value":580},{"type":413,"tag":501,"props":2127,"children":2128},{"style":583},[2129],{"type":418,"value":2130},"https://api.ipify.org",{"type":413,"tag":501,"props":2132,"children":2133},{"style":519},[2134],{"type":418,"value":580},{"type":413,"tag":501,"props":2136,"children":2137},{"style":519},[2138],{"type":418,"value":2139},"));\n",{"type":413,"tag":466,"props":2141,"children":2142},{"icon":468},[2143],{"type":413,"tag":414,"props":2144,"children":2145},{},[2146,2148,2154,2156,2162,2164,2171],{"type":418,"value":2147},"You can note here that we are just using standard C# code with an ",{"type":413,"tag":443,"props":2149,"children":2151},{"className":2150},[],[2152],{"type":418,"value":2153},"HttpClient",{"type":418,"value":2155}," that makes a ",{"type":413,"tag":443,"props":2157,"children":2159},{"className":2158},[],[2160],{"type":418,"value":2161},"GET",{"type":418,"value":2163}," to the API and returns asynchronously a string. I like the fact that with Pulumi we can reuse our existing C# skills, and the libraries we are used to. If we were to do that in Terraform we would have to look in the documentation how to do HTTP calls, discover that there is an ",{"type":413,"tag":432,"props":2165,"children":2168},{"href":2166,"rel":2167},"https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http",[436],[2169],{"type":418,"value":2170},"http data source",{"type":418,"value":2172}," that can be used, understand how it works (to be honest it seems quite simple but still that is not natural) and use it.",{"type":413,"tag":414,"props":2174,"children":2175},{},[2176],{"type":418,"value":2177},"Now we can enable this public IP by creating a firewall rule in the SQL Server.",{"type":413,"tag":492,"props":2179,"children":2181},{"className":494,"code":2180,"language":326,"meta":401,"style":401},"var enableLocalMachine = new FirewallRule(\"AllowLocalMachine\", new FirewallRuleArgs\n{\n    ResourceGroupName = resourceGroup.Name,\n    ServerName = sqlServer.Name,\n    StartIpAddress = publicIp,\n    EndIpAddress = publicIp\n});\n",[2182],{"type":413,"tag":443,"props":2183,"children":2184},{"__ignoreMap":401},[2185,2240,2247,2274,2301,2321,2338],{"type":413,"tag":501,"props":2186,"children":2187},{"class":503,"line":504},[2188,2192,2197,2201,2205,2210,2214,2218,2223,2227,2231,2235],{"type":413,"tag":501,"props":2189,"children":2190},{"style":508},[2191],{"type":418,"value":511},{"type":413,"tag":501,"props":2193,"children":2194},{"style":508},[2195],{"type":418,"value":2196}," enableLocalMachine",{"type":413,"tag":501,"props":2198,"children":2199},{"style":519},[2200],{"type":418,"value":522},{"type":413,"tag":501,"props":2202,"children":2203},{"style":519},[2204],{"type":418,"value":527},{"type":413,"tag":501,"props":2206,"children":2207},{"style":508},[2208],{"type":418,"value":2209}," FirewallRule",{"type":413,"tag":501,"props":2211,"children":2212},{"style":519},[2213],{"type":418,"value":575},{"type":413,"tag":501,"props":2215,"children":2216},{"style":519},[2217],{"type":418,"value":580},{"type":413,"tag":501,"props":2219,"children":2220},{"style":583},[2221],{"type":418,"value":2222},"AllowLocalMachine",{"type":413,"tag":501,"props":2224,"children":2225},{"style":519},[2226],{"type":418,"value":580},{"type":413,"tag":501,"props":2228,"children":2229},{"style":519},[2230],{"type":418,"value":704},{"type":413,"tag":501,"props":2232,"children":2233},{"style":519},[2234],{"type":418,"value":527},{"type":413,"tag":501,"props":2236,"children":2237},{"style":508},[2238],{"type":418,"value":2239}," FirewallRuleArgs\n",{"type":413,"tag":501,"props":2241,"children":2242},{"class":503,"line":540},[2243],{"type":413,"tag":501,"props":2244,"children":2245},{"style":519},[2246],{"type":418,"value":722},{"type":413,"tag":501,"props":2248,"children":2249},{"class":503,"line":598},[2250,2254,2258,2262,2266,2270],{"type":413,"tag":501,"props":2251,"children":2252},{"style":557},[2253],{"type":418,"value":951},{"type":413,"tag":501,"props":2255,"children":2256},{"style":519},[2257],{"type":418,"value":736},{"type":413,"tag":501,"props":2259,"children":2260},{"style":557},[2261],{"type":418,"value":960},{"type":413,"tag":501,"props":2263,"children":2264},{"style":519},[2265],{"type":418,"value":564},{"type":413,"tag":501,"props":2267,"children":2268},{"style":557},[2269],{"type":418,"value":969},{"type":413,"tag":501,"props":2271,"children":2272},{"style":519},[2273],{"type":418,"value":745},{"type":413,"tag":501,"props":2275,"children":2276},{"class":503,"line":649},[2277,2281,2285,2289,2293,2297],{"type":413,"tag":501,"props":2278,"children":2279},{"style":557},[2280],{"type":418,"value":1275},{"type":413,"tag":501,"props":2282,"children":2283},{"style":519},[2284],{"type":418,"value":736},{"type":413,"tag":501,"props":2286,"children":2287},{"style":557},[2288],{"type":418,"value":863},{"type":413,"tag":501,"props":2290,"children":2291},{"style":519},[2292],{"type":418,"value":564},{"type":413,"tag":501,"props":2294,"children":2295},{"style":557},[2296],{"type":418,"value":969},{"type":413,"tag":501,"props":2298,"children":2299},{"style":519},[2300],{"type":418,"value":745},{"type":413,"tag":501,"props":2302,"children":2303},{"class":503,"line":659},[2304,2309,2313,2317],{"type":413,"tag":501,"props":2305,"children":2306},{"style":557},[2307],{"type":418,"value":2308},"    StartIpAddress ",{"type":413,"tag":501,"props":2310,"children":2311},{"style":519},[2312],{"type":418,"value":736},{"type":413,"tag":501,"props":2314,"children":2315},{"style":557},[2316],{"type":418,"value":2079},{"type":413,"tag":501,"props":2318,"children":2319},{"style":519},[2320],{"type":418,"value":745},{"type":413,"tag":501,"props":2322,"children":2323},{"class":503,"line":716},[2324,2329,2333],{"type":413,"tag":501,"props":2325,"children":2326},{"style":557},[2327],{"type":418,"value":2328},"    EndIpAddress ",{"type":413,"tag":501,"props":2330,"children":2331},{"style":519},[2332],{"type":418,"value":736},{"type":413,"tag":501,"props":2334,"children":2335},{"style":557},[2336],{"type":418,"value":2337}," publicIp\n",{"type":413,"tag":501,"props":2339,"children":2340},{"class":503,"line":725},[2341],{"type":413,"tag":501,"props":2342,"children":2343},{"style":519},[2344],{"type":418,"value":803},{"type":413,"tag":1556,"props":2346,"children":2348},{"id":2347},"create-the-azure-ad-group-that-will-be-given-access-to-the-database",[2349],{"type":418,"value":2350},"Create the Azure AD group that will be given access to the database",{"type":413,"tag":414,"props":2352,"children":2353},{},[2354],{"type":418,"value":2355},"We said we wanted to grant SQL Database access to an Azure AD group that will contain in the future users and application managed identities that need access to the database. So let's create that:",{"type":413,"tag":492,"props":2357,"children":2359},{"className":494,"code":2358,"language":326,"meta":401,"style":401},"var sqlDatabaseAuthorizedGroup = new Group(\"SqlDbUsersGroup\", new GroupArgs\n{\n    DisplayName = \"SqlDbUsersGroup\",\n    SecurityEnabled = true,\n    Owners = new InputList\u003Cstring> { sqlAdAdmin.Id }\n});\n",[2360],{"type":413,"tag":443,"props":2361,"children":2362},{"__ignoreMap":401},[2363,2418,2425,2452,2472,2531],{"type":413,"tag":501,"props":2364,"children":2365},{"class":503,"line":504},[2366,2370,2375,2379,2383,2388,2392,2396,2401,2405,2409,2413],{"type":413,"tag":501,"props":2367,"children":2368},{"style":508},[2369],{"type":418,"value":511},{"type":413,"tag":501,"props":2371,"children":2372},{"style":508},[2373],{"type":418,"value":2374}," sqlDatabaseAuthorizedGroup",{"type":413,"tag":501,"props":2376,"children":2377},{"style":519},[2378],{"type":418,"value":522},{"type":413,"tag":501,"props":2380,"children":2381},{"style":519},[2382],{"type":418,"value":527},{"type":413,"tag":501,"props":2384,"children":2385},{"style":508},[2386],{"type":418,"value":2387}," Group",{"type":413,"tag":501,"props":2389,"children":2390},{"style":519},[2391],{"type":418,"value":575},{"type":413,"tag":501,"props":2393,"children":2394},{"style":519},[2395],{"type":418,"value":580},{"type":413,"tag":501,"props":2397,"children":2398},{"style":583},[2399],{"type":418,"value":2400},"SqlDbUsersGroup",{"type":413,"tag":501,"props":2402,"children":2403},{"style":519},[2404],{"type":418,"value":580},{"type":413,"tag":501,"props":2406,"children":2407},{"style":519},[2408],{"type":418,"value":704},{"type":413,"tag":501,"props":2410,"children":2411},{"style":519},[2412],{"type":418,"value":527},{"type":413,"tag":501,"props":2414,"children":2415},{"style":508},[2416],{"type":418,"value":2417}," GroupArgs\n",{"type":413,"tag":501,"props":2419,"children":2420},{"class":503,"line":540},[2421],{"type":413,"tag":501,"props":2422,"children":2423},{"style":519},[2424],{"type":418,"value":722},{"type":413,"tag":501,"props":2426,"children":2427},{"class":503,"line":598},[2428,2432,2436,2440,2444,2448],{"type":413,"tag":501,"props":2429,"children":2430},{"style":557},[2431],{"type":418,"value":775},{"type":413,"tag":501,"props":2433,"children":2434},{"style":519},[2435],{"type":418,"value":736},{"type":413,"tag":501,"props":2437,"children":2438},{"style":519},[2439],{"type":418,"value":784},{"type":413,"tag":501,"props":2441,"children":2442},{"style":583},[2443],{"type":418,"value":2400},{"type":413,"tag":501,"props":2445,"children":2446},{"style":519},[2447],{"type":418,"value":580},{"type":413,"tag":501,"props":2449,"children":2450},{"style":519},[2451],{"type":418,"value":745},{"type":413,"tag":501,"props":2453,"children":2454},{"class":503,"line":649},[2455,2460,2464,2468],{"type":413,"tag":501,"props":2456,"children":2457},{"style":557},[2458],{"type":418,"value":2459},"    SecurityEnabled ",{"type":413,"tag":501,"props":2461,"children":2462},{"style":519},[2463],{"type":418,"value":736},{"type":413,"tag":501,"props":2465,"children":2466},{"style":1075},[2467],{"type":418,"value":1078},{"type":413,"tag":501,"props":2469,"children":2470},{"style":519},[2471],{"type":418,"value":745},{"type":413,"tag":501,"props":2473,"children":2474},{"class":503,"line":659},[2475,2480,2484,2488,2493,2498,2503,2508,2513,2517,2521,2526],{"type":413,"tag":501,"props":2476,"children":2477},{"style":557},[2478],{"type":418,"value":2479},"    Owners ",{"type":413,"tag":501,"props":2481,"children":2482},{"style":519},[2483],{"type":418,"value":736},{"type":413,"tag":501,"props":2485,"children":2486},{"style":519},[2487],{"type":418,"value":527},{"type":413,"tag":501,"props":2489,"children":2490},{"style":508},[2491],{"type":418,"value":2492}," InputList",{"type":413,"tag":501,"props":2494,"children":2495},{"style":519},[2496],{"type":418,"value":2497},"\u003C",{"type":413,"tag":501,"props":2499,"children":2500},{"style":519},[2501],{"type":418,"value":2502},"string",{"type":413,"tag":501,"props":2504,"children":2505},{"style":519},[2506],{"type":418,"value":2507},">",{"type":413,"tag":501,"props":2509,"children":2510},{"style":519},[2511],{"type":418,"value":2512}," {",{"type":413,"tag":501,"props":2514,"children":2515},{"style":557},[2516],{"type":418,"value":669},{"type":413,"tag":501,"props":2518,"children":2519},{"style":519},[2520],{"type":418,"value":564},{"type":413,"tag":501,"props":2522,"children":2523},{"style":557},[2524],{"type":418,"value":2525},"Id ",{"type":413,"tag":501,"props":2527,"children":2528},{"style":519},[2529],{"type":418,"value":2530},"}\n",{"type":413,"tag":501,"props":2532,"children":2533},{"class":503,"line":716},[2534],{"type":413,"tag":501,"props":2535,"children":2536},{"style":519},[2537],{"type":418,"value":803},{"type":413,"tag":414,"props":2539,"children":2540},{},[2541],{"type":418,"value":2542},"We set the Azure SQL Server admin as the owner of the group. This way, the admin of the database can add Azure AD users to the group and they directly have the permissions configured for this group. I like authorizing an Azure AD group instead of each Azure AD user because:",{"type":413,"tag":1523,"props":2544,"children":2545},{},[2546,2551,2556],{"type":413,"tag":1527,"props":2547,"children":2548},{},[2549],{"type":418,"value":2550},"it is easier to manage a group than individual users (adding a user to a group is less work than using SQL commands to assign the correct role for each user)",{"type":413,"tag":1527,"props":2552,"children":2553},{},[2554],{"type":418,"value":2555},"you don't lose granularity of access control (you can always create several groups with different permissions if you need to)",{"type":413,"tag":1527,"props":2557,"children":2558},{},[2559],{"type":418,"value":2560},"you can ensure that your application runs with the same permissions locally (the code you debug uses your user account identity) and on Azure (the code uses the managed identity of the App Service where it is hosted) by putting users and managed identities in the same group",{"type":413,"tag":1556,"props":2562,"children":2564},{"id":2563},"assign-the-roles-to-the-azure-ad-group-using-the-command-provider",[2565],{"type":418,"value":2566},"Assign the roles to the Azure AD group using the Command provider",{"type":413,"tag":414,"props":2568,"children":2569},{},[2570,2572,2577,2579,2584],{"type":418,"value":2571},"As we already talked about, we can specify a script to run on the ",{"type":413,"tag":443,"props":2573,"children":2575},{"className":2574},[],[2576],{"type":418,"value":1952},{"type":418,"value":2578}," operation and another on the ",{"type":413,"tag":443,"props":2580,"children":2582},{"className":2581},[],[2583],{"type":418,"value":1982},{"type":418,"value":2585}," operations. To keep things simple for this sample, we will only handle the creation scenario where we will add our Azure AD group as a user of the database and give it the expected roles. We already showed the SQL Command to execute, with our new group name it becomes:",{"type":413,"tag":492,"props":2587,"children":2589},{"className":1390,"code":2588,"language":1392,"meta":401,"style":401},"CREATE USER {sqlDatabaseAuthorizedGroup.DisplayName} FROM EXTERNAL PROVIDER;\nALTER ROLE db_datareader ADD MEMBER {sqlDatabaseAuthorizedGroup.DisplayName};\nALTER ROLE db_datawriter ADD MEMBER {sqlDatabaseAuthorizedGroup.DisplayName};\nGO\n",[2590],{"type":413,"tag":443,"props":2591,"children":2592},{"__ignoreMap":401},[2593,2621,2645,2668],{"type":413,"tag":501,"props":2594,"children":2595},{"class":503,"line":504},[2596,2600,2605,2609,2613,2617],{"type":413,"tag":501,"props":2597,"children":2598},{"style":1402},[2599],{"type":418,"value":1405},{"type":413,"tag":501,"props":2601,"children":2602},{"style":557},[2603],{"type":418,"value":2604}," USER {sqlDatabaseAuthorizedGroup.DisplayName} ",{"type":413,"tag":501,"props":2606,"children":2607},{"style":1402},[2608],{"type":418,"value":1415},{"type":413,"tag":501,"props":2610,"children":2611},{"style":1402},[2612],{"type":418,"value":1420},{"type":413,"tag":501,"props":2614,"children":2615},{"style":1402},[2616],{"type":418,"value":1425},{"type":413,"tag":501,"props":2618,"children":2619},{"style":557},[2620],{"type":418,"value":1430},{"type":413,"tag":501,"props":2622,"children":2623},{"class":503,"line":540},[2624,2628,2632,2636,2640],{"type":413,"tag":501,"props":2625,"children":2626},{"style":1402},[2627],{"type":418,"value":1438},{"type":413,"tag":501,"props":2629,"children":2630},{"style":1402},[2631],{"type":418,"value":1443},{"type":413,"tag":501,"props":2633,"children":2634},{"style":557},[2635],{"type":418,"value":1448},{"type":413,"tag":501,"props":2637,"children":2638},{"style":1402},[2639],{"type":418,"value":1453},{"type":413,"tag":501,"props":2641,"children":2642},{"style":557},[2643],{"type":418,"value":2644}," MEMBER {sqlDatabaseAuthorizedGroup.DisplayName};\n",{"type":413,"tag":501,"props":2646,"children":2647},{"class":503,"line":598},[2648,2652,2656,2660,2664],{"type":413,"tag":501,"props":2649,"children":2650},{"style":1402},[2651],{"type":418,"value":1438},{"type":413,"tag":501,"props":2653,"children":2654},{"style":1402},[2655],{"type":418,"value":1443},{"type":413,"tag":501,"props":2657,"children":2658},{"style":557},[2659],{"type":418,"value":1474},{"type":413,"tag":501,"props":2661,"children":2662},{"style":1402},[2663],{"type":418,"value":1453},{"type":413,"tag":501,"props":2665,"children":2666},{"style":557},[2667],{"type":418,"value":2644},{"type":413,"tag":501,"props":2669,"children":2670},{"class":503,"line":649},[2671],{"type":413,"tag":501,"props":2672,"children":2673},{"style":1402},[2674],{"type":418,"value":1490},{"type":413,"tag":414,"props":2676,"children":2677},{},[2678,2680,2685],{"type":418,"value":2679},"The ",{"type":413,"tag":443,"props":2681,"children":2683},{"className":2682},[],[2684],{"type":418,"value":1547},{"type":418,"value":2686}," utility can be used like this to send a command on the database:",{"type":413,"tag":492,"props":2688,"children":2691},{"className":2689,"code":2690,"language":248,"meta":401,"style":401},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","sqlcmd -S {sqlServer.Name}.database.windows.net -d {database.Name} -U {sqlAdAdmin.UserPrincipalName} -P {sqlAdAdmin.Password} -G -l 30 -Q '___SQL Command___'\n",[2692],{"type":413,"tag":443,"props":2693,"children":2694},{"__ignoreMap":401},[2695],{"type":413,"tag":501,"props":2696,"children":2697},{"class":503,"line":504},[2698,2703,2708,2713,2717,2722,2727,2732,2736,2741,2745,2750,2754,2759,2764,2768,2773,2777,2781,2786,2790,2795,2799,2803,2808,2812,2817,2822,2826,2831,2836,2841],{"type":413,"tag":501,"props":2699,"children":2700},{"style":557},[2701],{"type":418,"value":2702},"sqlcmd ",{"type":413,"tag":501,"props":2704,"children":2705},{"style":519},[2706],{"type":418,"value":2707},"-",{"type":413,"tag":501,"props":2709,"children":2710},{"style":557},[2711],{"type":418,"value":2712},"S ",{"type":413,"tag":501,"props":2714,"children":2715},{"style":519},[2716],{"type":418,"value":895},{"type":413,"tag":501,"props":2718,"children":2719},{"style":557},[2720],{"type":418,"value":2721},"sqlServer.Name",{"type":413,"tag":501,"props":2723,"children":2724},{"style":519},[2725],{"type":418,"value":2726},"}",{"type":413,"tag":501,"props":2728,"children":2729},{"style":557},[2730],{"type":418,"value":2731},".database.windows.net ",{"type":413,"tag":501,"props":2733,"children":2734},{"style":519},[2735],{"type":418,"value":2707},{"type":413,"tag":501,"props":2737,"children":2738},{"style":557},[2739],{"type":418,"value":2740},"d ",{"type":413,"tag":501,"props":2742,"children":2743},{"style":519},[2744],{"type":418,"value":895},{"type":413,"tag":501,"props":2746,"children":2747},{"style":557},[2748],{"type":418,"value":2749},"database.Name",{"type":413,"tag":501,"props":2751,"children":2752},{"style":519},[2753],{"type":418,"value":2726},{"type":413,"tag":501,"props":2755,"children":2756},{"style":519},[2757],{"type":418,"value":2758}," -",{"type":413,"tag":501,"props":2760,"children":2761},{"style":557},[2762],{"type":418,"value":2763},"U ",{"type":413,"tag":501,"props":2765,"children":2766},{"style":519},[2767],{"type":418,"value":895},{"type":413,"tag":501,"props":2769,"children":2770},{"style":557},[2771],{"type":418,"value":2772},"sqlAdAdmin.UserPrincipalName",{"type":413,"tag":501,"props":2774,"children":2775},{"style":519},[2776],{"type":418,"value":2726},{"type":413,"tag":501,"props":2778,"children":2779},{"style":519},[2780],{"type":418,"value":2758},{"type":413,"tag":501,"props":2782,"children":2783},{"style":557},[2784],{"type":418,"value":2785},"P ",{"type":413,"tag":501,"props":2787,"children":2788},{"style":519},[2789],{"type":418,"value":895},{"type":413,"tag":501,"props":2791,"children":2792},{"style":557},[2793],{"type":418,"value":2794},"sqlAdAdmin.Password",{"type":413,"tag":501,"props":2796,"children":2797},{"style":519},[2798],{"type":418,"value":2726},{"type":413,"tag":501,"props":2800,"children":2801},{"style":519},[2802],{"type":418,"value":2758},{"type":413,"tag":501,"props":2804,"children":2805},{"style":557},[2806],{"type":418,"value":2807},"G ",{"type":413,"tag":501,"props":2809,"children":2810},{"style":519},[2811],{"type":418,"value":2707},{"type":413,"tag":501,"props":2813,"children":2814},{"style":557},[2815],{"type":418,"value":2816},"l ",{"type":413,"tag":501,"props":2818,"children":2819},{"style":1402},[2820],{"type":418,"value":2821},"30",{"type":413,"tag":501,"props":2823,"children":2824},{"style":519},[2825],{"type":418,"value":2758},{"type":413,"tag":501,"props":2827,"children":2828},{"style":557},[2829],{"type":418,"value":2830},"Q ",{"type":413,"tag":501,"props":2832,"children":2833},{"style":519},[2834],{"type":418,"value":2835},"'",{"type":413,"tag":501,"props":2837,"children":2838},{"style":583},[2839],{"type":418,"value":2840},"___SQL Command___",{"type":413,"tag":501,"props":2842,"children":2843},{"style":519},[2844],{"type":418,"value":2845},"'\n",{"type":413,"tag":414,"props":2847,"children":2848},{},[2849,2851,2858,2860,2865],{"type":418,"value":2850},"You can check the ",{"type":413,"tag":432,"props":2852,"children":2855},{"href":2853,"rel":2854},"https://docs.microsoft.com/en-us/sql/tools/sqlcmd-utility?view=sql-server-ver15#sqlcmd-commands",[436],[2856],{"type":418,"value":2857},"documentation",{"type":418,"value":2859}," to learn more about how to use ",{"type":413,"tag":443,"props":2861,"children":2863},{"className":2862},[],[2864],{"type":418,"value":1547},{"type":418,"value":2866}," but that is quite simple: we are just specifying to send a command line query on our database using Azure Active Directory to authenticate.",{"type":413,"tag":414,"props":2868,"children":2869},{},[2870],{"type":418,"value":2871},"If we use all that with our Command provider, we get the following C# code.",{"type":413,"tag":492,"props":2873,"children":2875},{"className":494,"code":2874,"language":326,"meta":401,"style":401},"var authorizeAdGroup = new Command(\"AuthorizeAdGroup\", new CommandArgs\n{\n    Create = Output.Format($\"sqlcmd -S {sqlServer.Name}.database.windows.net -d {database.Name} -U {sqlAdAdmin.UserPrincipalName} -P {sqlAdAdmin.Password} -G -l 30 -Q 'CREATE USER {sqlDatabaseAuthorizedGroup.DisplayName} FROM EXTERNAL PROVIDER; ALTER ROLE db_datareader ADD MEMBER {sqlDatabaseAuthorizedGroup.DisplayName}; ALTER ROLE db_datawriter ADD MEMBER {sqlDatabaseAuthorizedGroup.DisplayName};'\"),\n    Interpreter = new InputList\u003Cstring>\n    {\n        \"pwsh\",\n        \"-c\"\n    }\n});\n",[2876],{"type":413,"tag":443,"props":2877,"children":2878},{"__ignoreMap":401},[2879,2934,2941,3167,3200,3207,3228,3244,3251],{"type":413,"tag":501,"props":2880,"children":2881},{"class":503,"line":504},[2882,2886,2891,2895,2899,2904,2908,2912,2917,2921,2925,2929],{"type":413,"tag":501,"props":2883,"children":2884},{"style":508},[2885],{"type":418,"value":511},{"type":413,"tag":501,"props":2887,"children":2888},{"style":508},[2889],{"type":418,"value":2890}," authorizeAdGroup",{"type":413,"tag":501,"props":2892,"children":2893},{"style":519},[2894],{"type":418,"value":522},{"type":413,"tag":501,"props":2896,"children":2897},{"style":519},[2898],{"type":418,"value":527},{"type":413,"tag":501,"props":2900,"children":2901},{"style":508},[2902],{"type":418,"value":2903}," Command",{"type":413,"tag":501,"props":2905,"children":2906},{"style":519},[2907],{"type":418,"value":575},{"type":413,"tag":501,"props":2909,"children":2910},{"style":519},[2911],{"type":418,"value":580},{"type":413,"tag":501,"props":2913,"children":2914},{"style":583},[2915],{"type":418,"value":2916},"AuthorizeAdGroup",{"type":413,"tag":501,"props":2918,"children":2919},{"style":519},[2920],{"type":418,"value":580},{"type":413,"tag":501,"props":2922,"children":2923},{"style":519},[2924],{"type":418,"value":704},{"type":413,"tag":501,"props":2926,"children":2927},{"style":519},[2928],{"type":418,"value":527},{"type":413,"tag":501,"props":2930,"children":2931},{"style":508},[2932],{"type":418,"value":2933}," CommandArgs\n",{"type":413,"tag":501,"props":2935,"children":2936},{"class":503,"line":540},[2937],{"type":413,"tag":501,"props":2938,"children":2939},{"style":519},[2940],{"type":418,"value":722},{"type":413,"tag":501,"props":2942,"children":2943},{"class":503,"line":598},[2944,2949,2953,2957,2961,2966,2970,2974,2979,2983,2988,2992,2996,3000,3005,3009,3013,3017,3021,3025,3030,3034,3038,3042,3046,3050,3055,3059,3063,3067,3072,3076,3081,3085,3090,3094,3099,3103,3108,3112,3116,3120,3124,3128,3133,3137,3141,3145,3149,3153,3158,3162],{"type":413,"tag":501,"props":2945,"children":2946},{"style":557},[2947],{"type":418,"value":2948},"    Create ",{"type":413,"tag":501,"props":2950,"children":2951},{"style":519},[2952],{"type":418,"value":736},{"type":413,"tag":501,"props":2954,"children":2955},{"style":557},[2956],{"type":418,"value":2088},{"type":413,"tag":501,"props":2958,"children":2959},{"style":519},[2960],{"type":418,"value":564},{"type":413,"tag":501,"props":2962,"children":2963},{"style":567},[2964],{"type":418,"value":2965},"Format",{"type":413,"tag":501,"props":2967,"children":2968},{"style":519},[2969],{"type":418,"value":575},{"type":413,"tag":501,"props":2971,"children":2972},{"style":519},[2973],{"type":418,"value":885},{"type":413,"tag":501,"props":2975,"children":2976},{"style":583},[2977],{"type":418,"value":2978},"sqlcmd -S ",{"type":413,"tag":501,"props":2980,"children":2981},{"style":519},[2982],{"type":418,"value":895},{"type":413,"tag":501,"props":2984,"children":2985},{"style":557},[2986],{"type":418,"value":2987},"sqlServer",{"type":413,"tag":501,"props":2989,"children":2990},{"style":519},[2991],{"type":418,"value":564},{"type":413,"tag":501,"props":2993,"children":2994},{"style":557},[2995],{"type":418,"value":969},{"type":413,"tag":501,"props":2997,"children":2998},{"style":519},[2999],{"type":418,"value":2726},{"type":413,"tag":501,"props":3001,"children":3002},{"style":583},[3003],{"type":418,"value":3004},".database.windows.net -d ",{"type":413,"tag":501,"props":3006,"children":3007},{"style":519},[3008],{"type":418,"value":895},{"type":413,"tag":501,"props":3010,"children":3011},{"style":557},[3012],{"type":418,"value":1723},{"type":413,"tag":501,"props":3014,"children":3015},{"style":519},[3016],{"type":418,"value":564},{"type":413,"tag":501,"props":3018,"children":3019},{"style":557},[3020],{"type":418,"value":969},{"type":413,"tag":501,"props":3022,"children":3023},{"style":519},[3024],{"type":418,"value":2726},{"type":413,"tag":501,"props":3026,"children":3027},{"style":583},[3028],{"type":418,"value":3029}," -U ",{"type":413,"tag":501,"props":3031,"children":3032},{"style":519},[3033],{"type":418,"value":895},{"type":413,"tag":501,"props":3035,"children":3036},{"style":557},[3037],{"type":418,"value":586},{"type":413,"tag":501,"props":3039,"children":3040},{"style":519},[3041],{"type":418,"value":564},{"type":413,"tag":501,"props":3043,"children":3044},{"style":557},[3045],{"type":418,"value":1027},{"type":413,"tag":501,"props":3047,"children":3048},{"style":519},[3049],{"type":418,"value":2726},{"type":413,"tag":501,"props":3051,"children":3052},{"style":583},[3053],{"type":418,"value":3054}," -P ",{"type":413,"tag":501,"props":3056,"children":3057},{"style":519},[3058],{"type":418,"value":895},{"type":413,"tag":501,"props":3060,"children":3061},{"style":557},[3062],{"type":418,"value":586},{"type":413,"tag":501,"props":3064,"children":3065},{"style":519},[3066],{"type":418,"value":564},{"type":413,"tag":501,"props":3068,"children":3069},{"style":557},[3070],{"type":418,"value":3071},"Password",{"type":413,"tag":501,"props":3073,"children":3074},{"style":519},[3075],{"type":418,"value":2726},{"type":413,"tag":501,"props":3077,"children":3078},{"style":583},[3079],{"type":418,"value":3080}," -G -l 30 -Q 'CREATE USER ",{"type":413,"tag":501,"props":3082,"children":3083},{"style":519},[3084],{"type":418,"value":895},{"type":413,"tag":501,"props":3086,"children":3087},{"style":557},[3088],{"type":418,"value":3089},"sqlDatabaseAuthorizedGroup",{"type":413,"tag":501,"props":3091,"children":3092},{"style":519},[3093],{"type":418,"value":564},{"type":413,"tag":501,"props":3095,"children":3096},{"style":557},[3097],{"type":418,"value":3098},"DisplayName",{"type":413,"tag":501,"props":3100,"children":3101},{"style":519},[3102],{"type":418,"value":2726},{"type":413,"tag":501,"props":3104,"children":3105},{"style":583},[3106],{"type":418,"value":3107}," FROM EXTERNAL PROVIDER; ALTER ROLE db_datareader ADD MEMBER ",{"type":413,"tag":501,"props":3109,"children":3110},{"style":519},[3111],{"type":418,"value":895},{"type":413,"tag":501,"props":3113,"children":3114},{"style":557},[3115],{"type":418,"value":3089},{"type":413,"tag":501,"props":3117,"children":3118},{"style":519},[3119],{"type":418,"value":564},{"type":413,"tag":501,"props":3121,"children":3122},{"style":557},[3123],{"type":418,"value":3098},{"type":413,"tag":501,"props":3125,"children":3126},{"style":519},[3127],{"type":418,"value":2726},{"type":413,"tag":501,"props":3129,"children":3130},{"style":583},[3131],{"type":418,"value":3132},"; ALTER ROLE db_datawriter ADD MEMBER ",{"type":413,"tag":501,"props":3134,"children":3135},{"style":519},[3136],{"type":418,"value":895},{"type":413,"tag":501,"props":3138,"children":3139},{"style":557},[3140],{"type":418,"value":3089},{"type":413,"tag":501,"props":3142,"children":3143},{"style":519},[3144],{"type":418,"value":564},{"type":413,"tag":501,"props":3146,"children":3147},{"style":557},[3148],{"type":418,"value":3098},{"type":413,"tag":501,"props":3150,"children":3151},{"style":519},[3152],{"type":418,"value":2726},{"type":413,"tag":501,"props":3154,"children":3155},{"style":583},[3156],{"type":418,"value":3157},";'",{"type":413,"tag":501,"props":3159,"children":3160},{"style":519},[3161],{"type":418,"value":580},{"type":413,"tag":501,"props":3163,"children":3164},{"style":519},[3165],{"type":418,"value":3166},"),\n",{"type":413,"tag":501,"props":3168,"children":3169},{"class":503,"line":649},[3170,3175,3179,3183,3187,3191,3195],{"type":413,"tag":501,"props":3171,"children":3172},{"style":557},[3173],{"type":418,"value":3174},"    Interpreter ",{"type":413,"tag":501,"props":3176,"children":3177},{"style":519},[3178],{"type":418,"value":736},{"type":413,"tag":501,"props":3180,"children":3181},{"style":519},[3182],{"type":418,"value":527},{"type":413,"tag":501,"props":3184,"children":3185},{"style":508},[3186],{"type":418,"value":2492},{"type":413,"tag":501,"props":3188,"children":3189},{"style":519},[3190],{"type":418,"value":2497},{"type":413,"tag":501,"props":3192,"children":3193},{"style":519},[3194],{"type":418,"value":2502},{"type":413,"tag":501,"props":3196,"children":3197},{"style":519},[3198],{"type":418,"value":3199},">\n",{"type":413,"tag":501,"props":3201,"children":3202},{"class":503,"line":659},[3203],{"type":413,"tag":501,"props":3204,"children":3205},{"style":519},[3206],{"type":418,"value":1002},{"type":413,"tag":501,"props":3208,"children":3209},{"class":503,"line":716},[3210,3215,3220,3224],{"type":413,"tag":501,"props":3211,"children":3212},{"style":519},[3213],{"type":418,"value":3214},"        \"",{"type":413,"tag":501,"props":3216,"children":3217},{"style":583},[3218],{"type":418,"value":3219},"pwsh",{"type":413,"tag":501,"props":3221,"children":3222},{"style":519},[3223],{"type":418,"value":580},{"type":413,"tag":501,"props":3225,"children":3226},{"style":519},[3227],{"type":418,"value":745},{"type":413,"tag":501,"props":3229,"children":3230},{"class":503,"line":725},[3231,3235,3240],{"type":413,"tag":501,"props":3232,"children":3233},{"style":519},[3234],{"type":418,"value":3214},{"type":413,"tag":501,"props":3236,"children":3237},{"style":583},[3238],{"type":418,"value":3239},"-c",{"type":413,"tag":501,"props":3241,"children":3242},{"style":519},[3243],{"type":418,"value":794},{"type":413,"tag":501,"props":3245,"children":3246},{"class":503,"line":748},[3247],{"type":413,"tag":501,"props":3248,"children":3249},{"style":519},[3250],{"type":418,"value":1356},{"type":413,"tag":501,"props":3252,"children":3253},{"class":503,"line":769},[3254],{"type":413,"tag":501,"props":3255,"children":3256},{"style":519},[3257],{"type":418,"value":803},{"type":413,"tag":414,"props":3259,"children":3260},{},[3261],{"type":418,"value":3262},"As you can see, we can specify a specific interpreter to use (PowerShell here).",{"type":413,"tag":466,"props":3264,"children":3265},{"icon":468},[3266],{"type":413,"tag":414,"props":3267,"children":3268},{},[3269,3271,3278,3280,3286,3288,3294],{"type":418,"value":3270},"Don't do like me and forget that our variables are ",{"type":413,"tag":432,"props":3272,"children":3275},{"href":3273,"rel":3274},"https://www.pulumi.com/docs/intro/concepts/inputs-outputs/#inputs-and-outputs",[436],[3276],{"type":418,"value":3277},"outputs",{"type":418,"value":3279}," (only fully known when the infrastructure resource is completely provisioned). Because of that it is necessary to use the ",{"type":413,"tag":443,"props":3281,"children":3283},{"className":3282},[],[3284],{"type":418,"value":3285},"Output.Format",{"type":418,"value":3287}," method for string interpolation instead of using the C# operator ",{"type":413,"tag":443,"props":3289,"children":3291},{"className":3290},[],[3292],{"type":418,"value":3293},"$",{"type":418,"value":3295},". Thanks to the community on Slack for helping me on that one because with the Command provider not logging the errors details I had a hard time on this.",{"type":413,"tag":1556,"props":3297,"children":3299},{"id":3298},"results",[3300],{"type":418,"value":3301},"Results",{"type":413,"tag":414,"props":3303,"children":3304},{},[3305,3307,3312,3313,3318],{"type":418,"value":3306},"And that's it! We now have created the Azure AD group as an external user in the database and assigned it the ",{"type":413,"tag":443,"props":3308,"children":3310},{"className":3309},[],[3311],{"type":418,"value":1501},{"type":418,"value":1503},{"type":413,"tag":443,"props":3314,"children":3316},{"className":3315},[],[3317],{"type":418,"value":1509},{"type":418,"value":3319}," roles.\nHere is what it looks like in Azure Data Studio:",{"type":413,"tag":414,"props":3321,"children":3322},{},[3323],{"type":413,"tag":1580,"props":3324,"children":3328},{"alt":3325,"className":3326,"src":3327},"SQL query listing database members and roles in Azure Data Studio.",[1584,1585],"/posts/images/sqldatabase_ad_azuredatastudio.png",[],{"type":413,"tag":420,"props":3330,"children":3332},{"id":3331},"conclusion",[3333],{"type":418,"value":3334},"Conclusion",{"type":413,"tag":414,"props":3336,"children":3337},{},[3338,3340,3346],{"type":418,"value":3339},"This article is a bit long because I explain all the steps and possibilities but the complete code is not very big or complex. You can find it in this ",{"type":413,"tag":432,"props":3341,"children":3344},{"href":3342,"rel":3343},"https://github.com/TechWatching/SqlDatabaseWithAzureAd",[436],[3345],{"type":418,"value":1617},{"type":418,"value":564},{"type":413,"tag":414,"props":3348,"children":3349},{},[3350],{"type":418,"value":3351},"I did not see that many articles on the web that talk about using Azure Active Directory authentication for an Azure SQL Database, and even less that showed how to properly configure it using Infrastructure as Code. Yet, I think it's an important thing to do to properly secure your Azure SQL database. So I hope you enjoyed it and learn something. Whether you use Azure CLI, Bicep, ARM Templates, Terraform, or Pulumi, don't hesitate to use Azure AD authentication on your Azure SQL Database, for me that is the right and secure way to go.",{"type":413,"tag":414,"props":3353,"children":3354},{},[3355],{"type":418,"value":3356},"As you have seen in this article, even when there is no provider for your custom resource or task, there are always several solutions to do what you want with Pulumi. Some are more elegant, some are more complex than others but you will always find a way and you will not be limited by the platform.",{"type":413,"tag":414,"props":3358,"children":3359},{},[3360],{"type":418,"value":3361},"A big thank you to the Pulumi community that gave me some insights on how to configure Azure AD authentication on a database properly using Pulumi. Without the help of some people in the Pulumi Slack or the GitHub Issues/Discussions I would not have been able to write this article. Indeed some ideas and solutions are directly inspired by people's answers to my questions. This article is my way of contributing back and helping others that would have similar questions.",{"type":413,"tag":3363,"props":3364,"children":3365},"style",{},[3366],{"type":418,"value":3367},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":401,"searchDepth":540,"depth":540,"links":3369},[3370,3371,3372,3373,3379,3385],{"id":422,"depth":540,"text":425},{"id":482,"depth":540,"text":485},{"id":836,"depth":540,"text":839},{"id":1366,"depth":540,"text":1369,"children":3374},[3375,3376,3377],{"id":1558,"depth":598,"text":1561},{"id":1659,"depth":598,"text":1662},{"id":1877,"depth":598,"text":3378},"Command provider with the sqlcmd utility",{"id":2019,"depth":540,"text":2022,"children":3380},[3381,3382,3383,3384],{"id":2044,"depth":598,"text":2047},{"id":2347,"depth":598,"text":2350},{"id":2563,"depth":598,"text":2566},{"id":3298,"depth":598,"text":3301},{"id":3331,"depth":540,"text":3334},"markdown","content:1.posts:35.sqldatabase-active-directory-authent.md","content","1.posts/35.sqldatabase-active-directory-authent.md","md",{"_path":67,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":66,"description":3392,"lead":3393,"date":3394,"image":3395,"badge":3397,"tags":3399,"body":3400,"_type":3386,"_id":5831,"_source":3388,"_file":5832,"_extension":3390},"In Microsoft.Data.SqlClient v3.0.0, a new authentication mode Active Directory Default has been released. Let's see what this means when querying an Azure SQL Database from some C# code.","Talking about Active Directory Default authentication mode for SqlClient.","2021-06-22T00:00:00.000Z",{"src":3396},"/images/cloud-azure_1.jpg",{"label":3398},"Development",[252,299,302,228,225,236],{"type":410,"children":3401,"toc":5820},[3402,3421,3444,3449,3455,3475,3601,3612,3617,3640,3645,3651,3656,3661,3674,3686,3890,3929,3934,3947,3981,4059,4075,4081,4086,4092,4106,5115,5120,5155,5160,5174,5180,5194,5207,5709,5714,5772,5781,5797,5803,5816],{"type":413,"tag":414,"props":3403,"children":3404},{},[3405,3406,3411,3413,3419],{"type":418,"value":430},{"type":413,"tag":443,"props":3407,"children":3409},{"className":3408},[],[3410],{"type":418,"value":448},{"type":418,"value":3412}," v3.0.0, a new authentication mode ",{"type":413,"tag":443,"props":3414,"children":3416},{"className":3415},[],[3417],{"type":418,"value":3418},"Active Directory Default",{"type":418,"value":3420}," has been released. Let's see what this means when querying an Azure SQL Database from some C# code.",{"type":413,"tag":466,"props":3422,"children":3423},{"icon":468},[3424],{"type":413,"tag":414,"props":3425,"children":3426},{},[3427,3429,3434,3436,3442],{"type":418,"value":3428},"If you do not have heard about ",{"type":413,"tag":443,"props":3430,"children":3432},{"className":3431},[],[3433],{"type":418,"value":448},{"type":418,"value":3435},", it is the new data provider for Microsoft SQL Server and Azure SQL Database which supports both .NET Framework and .NET Core and replace the old ",{"type":413,"tag":443,"props":3437,"children":3439},{"className":3438},[],[3440],{"type":418,"value":3441},"System.Data.SqlClient",{"type":418,"value":3443}," components.",{"type":413,"tag":414,"props":3445,"children":3446},{},[3447],{"type":418,"value":3448},"But first, let's talk about how we used to do that before.",{"type":413,"tag":420,"props":3450,"children":3452},{"id":3451},"the-traditional-way-using-a-secret-connection-string",[3453],{"type":418,"value":3454},"The traditional way: using a secret connection string",{"type":413,"tag":414,"props":3456,"children":3457},{},[3458,3459,3465,3467,3473],{"type":418,"value":2679},{"type":413,"tag":443,"props":3460,"children":3462},{"className":3461},[],[3463],{"type":418,"value":3464},"traditional way",{"type":418,"value":3466}," to connect to an Azure SQL database from an application in C# is to provide to the ",{"type":413,"tag":443,"props":3468,"children":3470},{"className":3469},[],[3471],{"type":418,"value":3472},"SqlConnection",{"type":418,"value":3474}," constructor a connection string that contains a username and a password. The corresponding C# code is quite simple:",{"type":413,"tag":492,"props":3476,"children":3478},{"className":494,"code":3477,"language":326,"meta":401,"style":401},"var connectionString = \"Server=server-testingmsi6499.database.windows.net; Database=database-testingmsi6499;User ID=globalSqlAdmin;Password=MySecretPassword;\");\n\nusing (var sqlConnection = new SqlConnection(connectionString));\nawait connection.OpenAsync();\n",[3479],{"type":413,"tag":443,"props":3480,"children":3481},{"__ignoreMap":401},[3482,3520,3527,3575],{"type":413,"tag":501,"props":3483,"children":3484},{"class":503,"line":504},[3485,3489,3494,3498,3502,3507,3511,3516],{"type":413,"tag":501,"props":3486,"children":3487},{"style":508},[3488],{"type":418,"value":511},{"type":413,"tag":501,"props":3490,"children":3491},{"style":508},[3492],{"type":418,"value":3493}," connectionString",{"type":413,"tag":501,"props":3495,"children":3496},{"style":519},[3497],{"type":418,"value":522},{"type":413,"tag":501,"props":3499,"children":3500},{"style":519},[3501],{"type":418,"value":784},{"type":413,"tag":501,"props":3503,"children":3504},{"style":583},[3505],{"type":418,"value":3506},"Server=server-testingmsi6499.database.windows.net; Database=database-testingmsi6499;User ID=globalSqlAdmin;Password=MySecretPassword;",{"type":413,"tag":501,"props":3508,"children":3509},{"style":519},[3510],{"type":418,"value":580},{"type":413,"tag":501,"props":3512,"children":3513},{"style":557},[3514],{"type":418,"value":3515},")",{"type":413,"tag":501,"props":3517,"children":3518},{"style":519},[3519],{"type":418,"value":1430},{"type":413,"tag":501,"props":3521,"children":3522},{"class":503,"line":540},[3523],{"type":413,"tag":501,"props":3524,"children":3525},{"emptyLinePlaceholder":653},[3526],{"type":418,"value":656},{"type":413,"tag":501,"props":3528,"children":3529},{"class":503,"line":598},[3530,3535,3540,3544,3549,3553,3557,3562,3566,3571],{"type":413,"tag":501,"props":3531,"children":3532},{"style":1812},[3533],{"type":418,"value":3534},"using",{"type":413,"tag":501,"props":3536,"children":3537},{"style":519},[3538],{"type":418,"value":3539}," (",{"type":413,"tag":501,"props":3541,"children":3542},{"style":508},[3543],{"type":418,"value":511},{"type":413,"tag":501,"props":3545,"children":3546},{"style":508},[3547],{"type":418,"value":3548}," sqlConnection",{"type":413,"tag":501,"props":3550,"children":3551},{"style":519},[3552],{"type":418,"value":522},{"type":413,"tag":501,"props":3554,"children":3555},{"style":519},[3556],{"type":418,"value":527},{"type":413,"tag":501,"props":3558,"children":3559},{"style":508},[3560],{"type":418,"value":3561}," SqlConnection",{"type":413,"tag":501,"props":3563,"children":3564},{"style":519},[3565],{"type":418,"value":575},{"type":413,"tag":501,"props":3567,"children":3568},{"style":557},[3569],{"type":418,"value":3570},"connectionString",{"type":413,"tag":501,"props":3572,"children":3573},{"style":519},[3574],{"type":418,"value":2139},{"type":413,"tag":501,"props":3576,"children":3577},{"class":503,"line":649},[3578,3583,3588,3592,3597],{"type":413,"tag":501,"props":3579,"children":3580},{"style":519},[3581],{"type":418,"value":3582},"await",{"type":413,"tag":501,"props":3584,"children":3585},{"style":557},[3586],{"type":418,"value":3587}," connection",{"type":413,"tag":501,"props":3589,"children":3590},{"style":519},[3591],{"type":418,"value":564},{"type":413,"tag":501,"props":3593,"children":3594},{"style":567},[3595],{"type":418,"value":3596},"OpenAsync",{"type":413,"tag":501,"props":3598,"children":3599},{"style":519},[3600],{"type":418,"value":537},{"type":413,"tag":414,"props":3602,"children":3603},{},[3604,3606,3611],{"type":418,"value":3605},"In that case, the connection string is a secret we must secure and not just by putting it in some configuration location everyone can have access to, but by storing it in a secured place like ",{"type":413,"tag":443,"props":3607,"children":3609},{"className":3608},[],[3610],{"type":418,"value":260},{"type":418,"value":564},{"type":413,"tag":414,"props":3613,"children":3614},{},[3615],{"type":418,"value":3616},"However, even if you secure it appropriately, using a connection string with a username/password in it has some disadvantages:",{"type":413,"tag":1523,"props":3618,"children":3619},{},[3620,3625,3630,3635],{"type":413,"tag":1527,"props":3621,"children":3622},{},[3623],{"type":418,"value":3624},"you need to handle who has access to it (so who has access to the key vault)",{"type":413,"tag":1527,"props":3626,"children":3627},{},[3628],{"type":418,"value":3629},"every application or every developer could potentially use the same connection string so auditing is not very convenient (for instance identifying in the database logs which user has run a specific transaction)",{"type":413,"tag":1527,"props":3631,"children":3632},{},[3633],{"type":418,"value":3634},"you only control who has access to the connection string in the key vault, not what people do with it (share it by email, store it on their local computer, ...) so not who can access the database",{"type":413,"tag":1527,"props":3636,"children":3637},{},[3638],{"type":418,"value":3639},"you need to handle the rotation of the secret, in other words, change the username/password regularly (because you can revoke the access to someone to the database, if he had access to the connection string at some point in time it is not a secret for him anymore)",{"type":413,"tag":414,"props":3641,"children":3642},{},[3643],{"type":418,"value":3644},"For all these reasons, using a secret connection string to connect to an Azure SQL Database is not the right approach.",{"type":413,"tag":420,"props":3646,"children":3648},{"id":3647},"the-new-way-using-azure-active-directory-authentication",[3649],{"type":418,"value":3650},"The new way: using Azure Active Directory Authentication",{"type":413,"tag":414,"props":3652,"children":3653},{},[3654],{"type":418,"value":3655},"Instead of using a secret connection string to connect to a database, the idea is to use the Azure Active Directory authentication mechanism. Azure Active Directory is the location that contains all the identities of your users and your applications in your company. So you can manage directly which identity (user or application) have access to a database.",{"type":413,"tag":414,"props":3657,"children":3658},{},[3659],{"type":418,"value":3660},"Applications or users that want to query a database will authenticate against Azure AD to retrieve an access token that will allow them to access the database using a connection string without any username nor password.",{"type":413,"tag":414,"props":3662,"children":3663},{},[3664,3666,3673],{"type":418,"value":3665},"If you want to know more about the advantages of using Azure AD authentication for connecting to an Azure SQL Database you can have a look in the ",{"type":413,"tag":432,"props":3667,"children":3670},{"href":3668,"rel":3669},"https://docs.microsoft.com/en-us/azure/azure-sql/database/authentication-aad-overview",[436],[3671],{"type":418,"value":3672},"official documentation",{"type":418,"value":564},{"type":413,"tag":414,"props":3675,"children":3676},{},[3677,3679,3684],{"type":418,"value":3678},"In the code we can remove the user id and password from the connection string but we have to retrieve an Azure AD access token and pass it to the ",{"type":413,"tag":443,"props":3680,"children":3682},{"className":3681},[],[3683],{"type":418,"value":3472},{"type":418,"value":3685}," instance:",{"type":413,"tag":492,"props":3687,"children":3689},{"className":494,"code":3688,"language":326,"meta":401,"style":401},"var accessToken = await new DefaultAzureCredential().GetTokenAsync(new TokenRequestContext(new string[] { \"https://database.windows.net//.default\" }));\nusing var connection = new SqlConnection(\"Server=server-testingmsi6499.database.windows.net; Database=database-testingmsi6499;\")\n{\n    AccessToken = accessToken.Token\n};\nawait connection.OpenAsync();\n",[3690],{"type":413,"tag":443,"props":3691,"children":3692},{"__ignoreMap":401},[3693,3777,3827,3834,3859,3867],{"type":413,"tag":501,"props":3694,"children":3695},{"class":503,"line":504},[3696,3700,3705,3709,3714,3718,3723,3727,3732,3736,3741,3745,3750,3755,3759,3763,3768,3772],{"type":413,"tag":501,"props":3697,"children":3698},{"style":508},[3699],{"type":418,"value":511},{"type":413,"tag":501,"props":3701,"children":3702},{"style":508},[3703],{"type":418,"value":3704}," accessToken",{"type":413,"tag":501,"props":3706,"children":3707},{"style":519},[3708],{"type":418,"value":522},{"type":413,"tag":501,"props":3710,"children":3711},{"style":519},[3712],{"type":418,"value":3713}," await",{"type":413,"tag":501,"props":3715,"children":3716},{"style":519},[3717],{"type":418,"value":527},{"type":413,"tag":501,"props":3719,"children":3720},{"style":508},[3721],{"type":418,"value":3722}," DefaultAzureCredential",{"type":413,"tag":501,"props":3724,"children":3725},{"style":519},[3726],{"type":418,"value":2112},{"type":413,"tag":501,"props":3728,"children":3729},{"style":567},[3730],{"type":418,"value":3731},"GetTokenAsync",{"type":413,"tag":501,"props":3733,"children":3734},{"style":519},[3735],{"type":418,"value":2102},{"type":413,"tag":501,"props":3737,"children":3738},{"style":508},[3739],{"type":418,"value":3740}," TokenRequestContext",{"type":413,"tag":501,"props":3742,"children":3743},{"style":519},[3744],{"type":418,"value":2102},{"type":413,"tag":501,"props":3746,"children":3747},{"style":519},[3748],{"type":418,"value":3749}," string",{"type":413,"tag":501,"props":3751,"children":3752},{"style":519},[3753],{"type":418,"value":3754},"[]",{"type":413,"tag":501,"props":3756,"children":3757},{"style":519},[3758],{"type":418,"value":2512},{"type":413,"tag":501,"props":3760,"children":3761},{"style":519},[3762],{"type":418,"value":784},{"type":413,"tag":501,"props":3764,"children":3765},{"style":583},[3766],{"type":418,"value":3767},"https://database.windows.net//.default",{"type":413,"tag":501,"props":3769,"children":3770},{"style":519},[3771],{"type":418,"value":580},{"type":413,"tag":501,"props":3773,"children":3774},{"style":519},[3775],{"type":418,"value":3776}," }));\n",{"type":413,"tag":501,"props":3778,"children":3779},{"class":503,"line":540},[3780,3784,3789,3793,3797,3801,3805,3809,3813,3818,3822],{"type":413,"tag":501,"props":3781,"children":3782},{"style":1812},[3783],{"type":418,"value":3534},{"type":413,"tag":501,"props":3785,"children":3786},{"style":508},[3787],{"type":418,"value":3788}," var",{"type":413,"tag":501,"props":3790,"children":3791},{"style":508},[3792],{"type":418,"value":3587},{"type":413,"tag":501,"props":3794,"children":3795},{"style":519},[3796],{"type":418,"value":522},{"type":413,"tag":501,"props":3798,"children":3799},{"style":519},[3800],{"type":418,"value":527},{"type":413,"tag":501,"props":3802,"children":3803},{"style":508},[3804],{"type":418,"value":3561},{"type":413,"tag":501,"props":3806,"children":3807},{"style":519},[3808],{"type":418,"value":575},{"type":413,"tag":501,"props":3810,"children":3811},{"style":519},[3812],{"type":418,"value":580},{"type":413,"tag":501,"props":3814,"children":3815},{"style":583},[3816],{"type":418,"value":3817},"Server=server-testingmsi6499.database.windows.net; Database=database-testingmsi6499;",{"type":413,"tag":501,"props":3819,"children":3820},{"style":519},[3821],{"type":418,"value":580},{"type":413,"tag":501,"props":3823,"children":3824},{"style":519},[3825],{"type":418,"value":3826},")\n",{"type":413,"tag":501,"props":3828,"children":3829},{"class":503,"line":598},[3830],{"type":413,"tag":501,"props":3831,"children":3832},{"style":519},[3833],{"type":418,"value":722},{"type":413,"tag":501,"props":3835,"children":3836},{"class":503,"line":649},[3837,3842,3846,3850,3854],{"type":413,"tag":501,"props":3838,"children":3839},{"style":557},[3840],{"type":418,"value":3841},"    AccessToken ",{"type":413,"tag":501,"props":3843,"children":3844},{"style":519},[3845],{"type":418,"value":736},{"type":413,"tag":501,"props":3847,"children":3848},{"style":557},[3849],{"type":418,"value":3704},{"type":413,"tag":501,"props":3851,"children":3852},{"style":519},[3853],{"type":418,"value":564},{"type":413,"tag":501,"props":3855,"children":3856},{"style":557},[3857],{"type":418,"value":3858},"Token\n",{"type":413,"tag":501,"props":3860,"children":3861},{"class":503,"line":659},[3862],{"type":413,"tag":501,"props":3863,"children":3864},{"style":519},[3865],{"type":418,"value":3866},"};\n",{"type":413,"tag":501,"props":3868,"children":3869},{"class":503,"line":716},[3870,3874,3878,3882,3886],{"type":413,"tag":501,"props":3871,"children":3872},{"style":519},[3873],{"type":418,"value":3582},{"type":413,"tag":501,"props":3875,"children":3876},{"style":557},[3877],{"type":418,"value":3587},{"type":413,"tag":501,"props":3879,"children":3880},{"style":519},[3881],{"type":418,"value":564},{"type":413,"tag":501,"props":3883,"children":3884},{"style":567},[3885],{"type":418,"value":3596},{"type":413,"tag":501,"props":3887,"children":3888},{"style":519},[3889],{"type":418,"value":537},{"type":413,"tag":414,"props":3891,"children":3892},{},[3893,3895,3902,3904,3910,3912,3919,3921,3927],{"type":418,"value":3894},"The code is using the ",{"type":413,"tag":432,"props":3896,"children":3899},{"href":3897,"rel":3898},"https://docs.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme",[436],[3900],{"type":418,"value":3901},"Azure Identity library",{"type":418,"value":3903}," which as the documentation says \"",{"type":413,"tag":3905,"props":3906,"children":3907},"em",{},[3908],{"type":418,"value":3909},"provides Azure Active Directory token authentication support across the Azure SDK",{"type":418,"value":3911},"\". It is the recommended way to get an Azure token although you may have seen code that uses another library ",{"type":413,"tag":432,"props":3913,"children":3916},{"href":3914,"rel":3915},"https://www.nuget.org/packages/Microsoft.Azure.Services.AppAuthentication",[436],[3917],{"type":418,"value":3918},"Microsoft.Azure.Services.AppAuthentication",{"type":418,"value":3920}," to do the same thing. The class ",{"type":413,"tag":443,"props":3922,"children":3924},{"className":3923},[],[3925],{"type":418,"value":3926},"DefaultAzureCredential",{"type":418,"value":3928}," from Azure Identity library combines multiple authentication mechanisms (like Managed Identities, Visual Studio, Azure CLI ...) that will be tried in order to retrieve a token so it is a practical class that can handle most of the scenarios.",{"type":413,"tag":414,"props":3930,"children":3931},{},[3932],{"type":418,"value":3933},"Therefore, provided that you have granted access to your database to the user you are using locally (in Visual Studio, in vs code, or in Azure CLI) and to the managed identity of your application in Azure (App Service or Azure Function for instance) the same code will work both locally and in Azure.",{"type":413,"tag":420,"props":3935,"children":3937},{"id":3936},"here-comes-active-directory-default-authentication-mode",[3938,3940,3945],{"type":418,"value":3939},"Here comes ",{"type":413,"tag":443,"props":3941,"children":3943},{"className":3942},[],[3944],{"type":418,"value":3418},{"type":418,"value":3946}," authentication mode",{"type":413,"tag":414,"props":3948,"children":3949},{},[3950,3952,3957,3959,3964,3966,3972,3974,3979],{"type":418,"value":3951},"We have seen that using Azure Active Directory Authentication was a better solution than using a connection string with secrets in it to connect to a database. However, it involves manually retrieving an Azure AD token which makes the code a bit more complex to read. That is exactly why ",{"type":413,"tag":443,"props":3953,"children":3955},{"className":3954},[],[3956],{"type":418,"value":3418},{"type":418,"value":3958}," new authentication mode was introduced in ",{"type":413,"tag":443,"props":3960,"children":3962},{"className":3961},[],[3963],{"type":418,"value":448},{"type":418,"value":3965}," v3.0.0. Under the hood, ",{"type":413,"tag":443,"props":3967,"children":3969},{"className":3968},[],[3970],{"type":418,"value":3971},"SqlClient",{"type":418,"value":3973}," does the same thing that we were showing previously so we don't have to do it ourselves: just specifying the authentication mode to ",{"type":413,"tag":443,"props":3975,"children":3977},{"className":3976},[],[3978],{"type":418,"value":3418},{"type":418,"value":3980}," in the connection string is enough to make it work.",{"type":413,"tag":492,"props":3982,"children":3984},{"className":494,"code":3983,"language":326,"meta":401,"style":401},"using var connection = new SqlConnection(\"Server=server-testingmsi6499.database.windows.net; Authentication=Active Directory Default; Database=database-testingmsi6499;\");\nawait connection.OpenAsync();\n",[3985],{"type":413,"tag":443,"props":3986,"children":3987},{"__ignoreMap":401},[3988,4036],{"type":413,"tag":501,"props":3989,"children":3990},{"class":503,"line":504},[3991,3995,3999,4003,4007,4011,4015,4019,4023,4028,4032],{"type":413,"tag":501,"props":3992,"children":3993},{"style":1812},[3994],{"type":418,"value":3534},{"type":413,"tag":501,"props":3996,"children":3997},{"style":508},[3998],{"type":418,"value":3788},{"type":413,"tag":501,"props":4000,"children":4001},{"style":508},[4002],{"type":418,"value":3587},{"type":413,"tag":501,"props":4004,"children":4005},{"style":519},[4006],{"type":418,"value":522},{"type":413,"tag":501,"props":4008,"children":4009},{"style":519},[4010],{"type":418,"value":527},{"type":413,"tag":501,"props":4012,"children":4013},{"style":508},[4014],{"type":418,"value":3561},{"type":413,"tag":501,"props":4016,"children":4017},{"style":519},[4018],{"type":418,"value":575},{"type":413,"tag":501,"props":4020,"children":4021},{"style":519},[4022],{"type":418,"value":580},{"type":413,"tag":501,"props":4024,"children":4025},{"style":583},[4026],{"type":418,"value":4027},"Server=server-testingmsi6499.database.windows.net; Authentication=Active Directory Default; Database=database-testingmsi6499;",{"type":413,"tag":501,"props":4029,"children":4030},{"style":519},[4031],{"type":418,"value":580},{"type":413,"tag":501,"props":4033,"children":4034},{"style":519},[4035],{"type":418,"value":595},{"type":413,"tag":501,"props":4037,"children":4038},{"class":503,"line":540},[4039,4043,4047,4051,4055],{"type":413,"tag":501,"props":4040,"children":4041},{"style":519},[4042],{"type":418,"value":3582},{"type":413,"tag":501,"props":4044,"children":4045},{"style":557},[4046],{"type":418,"value":3587},{"type":413,"tag":501,"props":4048,"children":4049},{"style":519},[4050],{"type":418,"value":564},{"type":413,"tag":501,"props":4052,"children":4053},{"style":567},[4054],{"type":418,"value":3596},{"type":413,"tag":501,"props":4056,"children":4057},{"style":519},[4058],{"type":418,"value":537},{"type":413,"tag":466,"props":4060,"children":4061},{"icon":468},[4062],{"type":413,"tag":414,"props":4063,"children":4064},{},[4065,4067,4074],{"type":418,"value":4066},"There are other Azure Active Directory authentication methods available, you can find them in the documentation ",{"type":413,"tag":432,"props":4068,"children":4071},{"href":4069,"rel":4070},"https://docs.microsoft.com/en-us/sql/connect/ado-net/sql/azure-active-directory-authentication?view=sql-server-ver15#using-active-directory-password-authentication",[436],[4072],{"type":418,"value":4073},"here",{"type":418,"value":564},{"type":413,"tag":420,"props":4076,"children":4078},{"id":4077},"a-complete-example",[4079],{"type":418,"value":4080},"A complete example",{"type":413,"tag":414,"props":4082,"children":4083},{},[4084],{"type":418,"value":4085},"Enough theory, what if you want to quickly test this by yourself?",{"type":413,"tag":1556,"props":4087,"children":4089},{"id":4088},"a-bit-of-azure-cli-to-initialize-the-database",[4090],{"type":418,"value":4091},"A bit of Azure CLI to initialize the database",{"type":413,"tag":414,"props":4093,"children":4094},{},[4095,4097,4104],{"type":418,"value":4096},"I took an ",{"type":413,"tag":432,"props":4098,"children":4101},{"href":4099,"rel":4100},"https://docs.microsoft.com/en-us/azure/azure-sql/database/scripts/create-and-configure-database-cli",[436],[4102],{"type":418,"value":4103},"Azure CLI sample script",{"type":418,"value":4105}," from Microsoft and modify it a little to configure a database with all that is necessary to use Azure Active Directory to connect my user to it.",{"type":413,"tag":492,"props":4107,"children":4111},{"className":4108,"code":4109,"language":4110,"meta":401,"style":401},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","#!/bin/bash\nlocation=\"West Europe\" # to change with your preferred location\nrandomIdentifier=testingmsi${RANDOM:0:5}\n\nresourceGroup=\"resource-$randomIdentifier\"\nserver=\"server-$randomIdentifier\"\ndatabase=\"database-$randomIdentifier\"\n\nlogin=\"globalSqlAdmin\"\npassword=\"P@ssw0rdToChange!\" # to change to have a more secured password\n\n# Retrieve your public IP.\n# Replace by your local machine IP if you are executing this script from cloud shell.\nstartIP=$(dig +short myip.opendns.com @resolver1.opendns.com)\nendIP=$startIP\n\n# Retrieve your current logged-in user to be used as SQL server admin. \n# Change with another user id if you want another user to be an admin.\nazureaduser=$(az ad signed-in-user show --query \"objectId\" -o tsv)\n\necho \"Creating $resourceGroup...\"\naz group create --name $resourceGroup --location \"$location\"\n\necho \"Creating $server in $location...\"\naz sql server create --name $server --resource-group $resourceGroup --location \"$location\" --admin-user $login --admin-password $password\n\necho \"Configuring firewall...\"\naz sql server firewall-rule create --resource-group $resourceGroup --server $server -n AllowYourIp --start-ip-address $startIP --end-ip-address $endIP\n\necho \"Creating $database on $server...\"\naz sql db create --resource-group $resourceGroup --server $server --name $database --sample-name AdventureWorksLT --service-objective Basic --zone-redundant false\n\necho \"Creating AD admin in sql server...\"\naz sql server ad-admin create --resource-group $resourceGroup --server-name $server --display-name ADMIN --object-id $azureaduser\n\necho \"Database connection string to use: \\\"Server=$server.database.windows.net; Authentication=Active Directory Default; Database=$database;\\\"\"\n","bash",[4112],{"type":413,"tag":443,"props":4113,"children":4114},{"__ignoreMap":401},[4115,4123,4153,4203,4210,4240,4269,4297,4304,4329,4359,4366,4374,4383,4421,4439,4447,4456,4465,4530,4538,4570,4616,4624,4662,4738,4746,4767,4840,4848,4886,4963,4971,4992,5054,5062],{"type":413,"tag":501,"props":4116,"children":4117},{"class":503,"line":504},[4118],{"type":413,"tag":501,"props":4119,"children":4120},{"style":1766},[4121],{"type":418,"value":4122},"#!/bin/bash\n",{"type":413,"tag":501,"props":4124,"children":4125},{"class":503,"line":540},[4126,4131,4135,4139,4144,4148],{"type":413,"tag":501,"props":4127,"children":4128},{"style":557},[4129],{"type":418,"value":4130},"location",{"type":413,"tag":501,"props":4132,"children":4133},{"style":519},[4134],{"type":418,"value":736},{"type":413,"tag":501,"props":4136,"children":4137},{"style":519},[4138],{"type":418,"value":580},{"type":413,"tag":501,"props":4140,"children":4141},{"style":583},[4142],{"type":418,"value":4143},"West Europe",{"type":413,"tag":501,"props":4145,"children":4146},{"style":519},[4147],{"type":418,"value":580},{"type":413,"tag":501,"props":4149,"children":4150},{"style":1766},[4151],{"type":418,"value":4152}," # to change with your preferred location\n",{"type":413,"tag":501,"props":4154,"children":4155},{"class":503,"line":598},[4156,4161,4165,4170,4175,4180,4185,4190,4194,4199],{"type":413,"tag":501,"props":4157,"children":4158},{"style":557},[4159],{"type":418,"value":4160},"randomIdentifier",{"type":413,"tag":501,"props":4162,"children":4163},{"style":519},[4164],{"type":418,"value":736},{"type":413,"tag":501,"props":4166,"children":4167},{"style":583},[4168],{"type":418,"value":4169},"testingmsi",{"type":413,"tag":501,"props":4171,"children":4172},{"style":519},[4173],{"type":418,"value":4174},"${",{"type":413,"tag":501,"props":4176,"children":4177},{"style":557},[4178],{"type":418,"value":4179},"RANDOM",{"type":413,"tag":501,"props":4181,"children":4182},{"style":519},[4183],{"type":418,"value":4184},":",{"type":413,"tag":501,"props":4186,"children":4187},{"style":557},[4188],{"type":418,"value":4189},"0",{"type":413,"tag":501,"props":4191,"children":4192},{"style":519},[4193],{"type":418,"value":4184},{"type":413,"tag":501,"props":4195,"children":4196},{"style":557},[4197],{"type":418,"value":4198},"5",{"type":413,"tag":501,"props":4200,"children":4201},{"style":519},[4202],{"type":418,"value":2530},{"type":413,"tag":501,"props":4204,"children":4205},{"class":503,"line":649},[4206],{"type":413,"tag":501,"props":4207,"children":4208},{"emptyLinePlaceholder":653},[4209],{"type":418,"value":656},{"type":413,"tag":501,"props":4211,"children":4212},{"class":503,"line":659},[4213,4218,4222,4226,4231,4236],{"type":413,"tag":501,"props":4214,"children":4215},{"style":557},[4216],{"type":418,"value":4217},"resourceGroup",{"type":413,"tag":501,"props":4219,"children":4220},{"style":519},[4221],{"type":418,"value":736},{"type":413,"tag":501,"props":4223,"children":4224},{"style":519},[4225],{"type":418,"value":580},{"type":413,"tag":501,"props":4227,"children":4228},{"style":583},[4229],{"type":418,"value":4230},"resource-",{"type":413,"tag":501,"props":4232,"children":4233},{"style":557},[4234],{"type":418,"value":4235},"$randomIdentifier",{"type":413,"tag":501,"props":4237,"children":4238},{"style":519},[4239],{"type":418,"value":794},{"type":413,"tag":501,"props":4241,"children":4242},{"class":503,"line":716},[4243,4248,4252,4256,4261,4265],{"type":413,"tag":501,"props":4244,"children":4245},{"style":557},[4246],{"type":418,"value":4247},"server",{"type":413,"tag":501,"props":4249,"children":4250},{"style":519},[4251],{"type":418,"value":736},{"type":413,"tag":501,"props":4253,"children":4254},{"style":519},[4255],{"type":418,"value":580},{"type":413,"tag":501,"props":4257,"children":4258},{"style":583},[4259],{"type":418,"value":4260},"server-",{"type":413,"tag":501,"props":4262,"children":4263},{"style":557},[4264],{"type":418,"value":4235},{"type":413,"tag":501,"props":4266,"children":4267},{"style":519},[4268],{"type":418,"value":794},{"type":413,"tag":501,"props":4270,"children":4271},{"class":503,"line":725},[4272,4276,4280,4284,4289,4293],{"type":413,"tag":501,"props":4273,"children":4274},{"style":557},[4275],{"type":418,"value":1723},{"type":413,"tag":501,"props":4277,"children":4278},{"style":519},[4279],{"type":418,"value":736},{"type":413,"tag":501,"props":4281,"children":4282},{"style":519},[4283],{"type":418,"value":580},{"type":413,"tag":501,"props":4285,"children":4286},{"style":583},[4287],{"type":418,"value":4288},"database-",{"type":413,"tag":501,"props":4290,"children":4291},{"style":557},[4292],{"type":418,"value":4235},{"type":413,"tag":501,"props":4294,"children":4295},{"style":519},[4296],{"type":418,"value":794},{"type":413,"tag":501,"props":4298,"children":4299},{"class":503,"line":748},[4300],{"type":413,"tag":501,"props":4301,"children":4302},{"emptyLinePlaceholder":653},[4303],{"type":418,"value":656},{"type":413,"tag":501,"props":4305,"children":4306},{"class":503,"line":769},[4307,4312,4316,4320,4325],{"type":413,"tag":501,"props":4308,"children":4309},{"style":557},[4310],{"type":418,"value":4311},"login",{"type":413,"tag":501,"props":4313,"children":4314},{"style":519},[4315],{"type":418,"value":736},{"type":413,"tag":501,"props":4317,"children":4318},{"style":519},[4319],{"type":418,"value":580},{"type":413,"tag":501,"props":4321,"children":4322},{"style":583},[4323],{"type":418,"value":4324},"globalSqlAdmin",{"type":413,"tag":501,"props":4326,"children":4327},{"style":519},[4328],{"type":418,"value":794},{"type":413,"tag":501,"props":4330,"children":4331},{"class":503,"line":797},[4332,4337,4341,4345,4350,4354],{"type":413,"tag":501,"props":4333,"children":4334},{"style":557},[4335],{"type":418,"value":4336},"password",{"type":413,"tag":501,"props":4338,"children":4339},{"style":519},[4340],{"type":418,"value":736},{"type":413,"tag":501,"props":4342,"children":4343},{"style":519},[4344],{"type":418,"value":580},{"type":413,"tag":501,"props":4346,"children":4347},{"style":583},[4348],{"type":418,"value":4349},"P@ssw0rdToChange!",{"type":413,"tag":501,"props":4351,"children":4352},{"style":519},[4353],{"type":418,"value":580},{"type":413,"tag":501,"props":4355,"children":4356},{"style":1766},[4357],{"type":418,"value":4358}," # to change to have a more secured password\n",{"type":413,"tag":501,"props":4360,"children":4361},{"class":503,"line":1145},[4362],{"type":413,"tag":501,"props":4363,"children":4364},{"emptyLinePlaceholder":653},[4365],{"type":418,"value":656},{"type":413,"tag":501,"props":4367,"children":4368},{"class":503,"line":1154},[4369],{"type":413,"tag":501,"props":4370,"children":4371},{"style":1766},[4372],{"type":418,"value":4373},"# Retrieve your public IP.\n",{"type":413,"tag":501,"props":4375,"children":4377},{"class":503,"line":4376},13,[4378],{"type":413,"tag":501,"props":4379,"children":4380},{"style":1766},[4381],{"type":418,"value":4382},"# Replace by your local machine IP if you are executing this script from cloud shell.\n",{"type":413,"tag":501,"props":4384,"children":4386},{"class":503,"line":4385},14,[4387,4392,4397,4402,4407,4412,4417],{"type":413,"tag":501,"props":4388,"children":4389},{"style":557},[4390],{"type":418,"value":4391},"startIP",{"type":413,"tag":501,"props":4393,"children":4394},{"style":519},[4395],{"type":418,"value":4396},"=$(",{"type":413,"tag":501,"props":4398,"children":4399},{"style":508},[4400],{"type":418,"value":4401},"dig",{"type":413,"tag":501,"props":4403,"children":4404},{"style":583},[4405],{"type":418,"value":4406}," +short",{"type":413,"tag":501,"props":4408,"children":4409},{"style":583},[4410],{"type":418,"value":4411}," myip.opendns.com",{"type":413,"tag":501,"props":4413,"children":4414},{"style":583},[4415],{"type":418,"value":4416}," @resolver1.opendns.com",{"type":413,"tag":501,"props":4418,"children":4419},{"style":519},[4420],{"type":418,"value":3826},{"type":413,"tag":501,"props":4422,"children":4424},{"class":503,"line":4423},15,[4425,4430,4434],{"type":413,"tag":501,"props":4426,"children":4427},{"style":557},[4428],{"type":418,"value":4429},"endIP",{"type":413,"tag":501,"props":4431,"children":4432},{"style":519},[4433],{"type":418,"value":736},{"type":413,"tag":501,"props":4435,"children":4436},{"style":557},[4437],{"type":418,"value":4438},"$startIP\n",{"type":413,"tag":501,"props":4440,"children":4442},{"class":503,"line":4441},16,[4443],{"type":413,"tag":501,"props":4444,"children":4445},{"emptyLinePlaceholder":653},[4446],{"type":418,"value":656},{"type":413,"tag":501,"props":4448,"children":4450},{"class":503,"line":4449},17,[4451],{"type":413,"tag":501,"props":4452,"children":4453},{"style":1766},[4454],{"type":418,"value":4455},"# Retrieve your current logged-in user to be used as SQL server admin. \n",{"type":413,"tag":501,"props":4457,"children":4459},{"class":503,"line":4458},18,[4460],{"type":413,"tag":501,"props":4461,"children":4462},{"style":1766},[4463],{"type":418,"value":4464},"# Change with another user id if you want another user to be an admin.\n",{"type":413,"tag":501,"props":4466,"children":4468},{"class":503,"line":4467},19,[4469,4474,4478,4483,4488,4493,4498,4503,4507,4512,4516,4521,4526],{"type":413,"tag":501,"props":4470,"children":4471},{"style":557},[4472],{"type":418,"value":4473},"azureaduser",{"type":413,"tag":501,"props":4475,"children":4476},{"style":519},[4477],{"type":418,"value":4396},{"type":413,"tag":501,"props":4479,"children":4480},{"style":508},[4481],{"type":418,"value":4482},"az",{"type":413,"tag":501,"props":4484,"children":4485},{"style":583},[4486],{"type":418,"value":4487}," ad",{"type":413,"tag":501,"props":4489,"children":4490},{"style":583},[4491],{"type":418,"value":4492}," signed-in-user",{"type":413,"tag":501,"props":4494,"children":4495},{"style":583},[4496],{"type":418,"value":4497}," show",{"type":413,"tag":501,"props":4499,"children":4500},{"style":583},[4501],{"type":418,"value":4502}," --query",{"type":413,"tag":501,"props":4504,"children":4505},{"style":519},[4506],{"type":418,"value":784},{"type":413,"tag":501,"props":4508,"children":4509},{"style":583},[4510],{"type":418,"value":4511},"objectId",{"type":413,"tag":501,"props":4513,"children":4514},{"style":519},[4515],{"type":418,"value":580},{"type":413,"tag":501,"props":4517,"children":4518},{"style":583},[4519],{"type":418,"value":4520}," -o",{"type":413,"tag":501,"props":4522,"children":4523},{"style":583},[4524],{"type":418,"value":4525}," tsv",{"type":413,"tag":501,"props":4527,"children":4528},{"style":519},[4529],{"type":418,"value":3826},{"type":413,"tag":501,"props":4531,"children":4533},{"class":503,"line":4532},20,[4534],{"type":413,"tag":501,"props":4535,"children":4536},{"emptyLinePlaceholder":653},[4537],{"type":418,"value":656},{"type":413,"tag":501,"props":4539,"children":4541},{"class":503,"line":4540},21,[4542,4547,4551,4556,4561,4566],{"type":413,"tag":501,"props":4543,"children":4544},{"style":567},[4545],{"type":418,"value":4546},"echo",{"type":413,"tag":501,"props":4548,"children":4549},{"style":519},[4550],{"type":418,"value":784},{"type":413,"tag":501,"props":4552,"children":4553},{"style":583},[4554],{"type":418,"value":4555},"Creating ",{"type":413,"tag":501,"props":4557,"children":4558},{"style":557},[4559],{"type":418,"value":4560},"$resourceGroup",{"type":413,"tag":501,"props":4562,"children":4563},{"style":583},[4564],{"type":418,"value":4565},"...",{"type":413,"tag":501,"props":4567,"children":4568},{"style":519},[4569],{"type":418,"value":794},{"type":413,"tag":501,"props":4571,"children":4573},{"class":503,"line":4572},22,[4574,4578,4583,4588,4593,4598,4603,4607,4612],{"type":413,"tag":501,"props":4575,"children":4576},{"style":508},[4577],{"type":418,"value":4482},{"type":413,"tag":501,"props":4579,"children":4580},{"style":583},[4581],{"type":418,"value":4582}," group",{"type":413,"tag":501,"props":4584,"children":4585},{"style":583},[4586],{"type":418,"value":4587}," create",{"type":413,"tag":501,"props":4589,"children":4590},{"style":583},[4591],{"type":418,"value":4592}," --name",{"type":413,"tag":501,"props":4594,"children":4595},{"style":557},[4596],{"type":418,"value":4597}," $resourceGroup ",{"type":413,"tag":501,"props":4599,"children":4600},{"style":583},[4601],{"type":418,"value":4602},"--location",{"type":413,"tag":501,"props":4604,"children":4605},{"style":519},[4606],{"type":418,"value":784},{"type":413,"tag":501,"props":4608,"children":4609},{"style":557},[4610],{"type":418,"value":4611},"$location",{"type":413,"tag":501,"props":4613,"children":4614},{"style":519},[4615],{"type":418,"value":794},{"type":413,"tag":501,"props":4617,"children":4619},{"class":503,"line":4618},23,[4620],{"type":413,"tag":501,"props":4621,"children":4622},{"emptyLinePlaceholder":653},[4623],{"type":418,"value":656},{"type":413,"tag":501,"props":4625,"children":4627},{"class":503,"line":4626},24,[4628,4632,4636,4640,4645,4650,4654,4658],{"type":413,"tag":501,"props":4629,"children":4630},{"style":567},[4631],{"type":418,"value":4546},{"type":413,"tag":501,"props":4633,"children":4634},{"style":519},[4635],{"type":418,"value":784},{"type":413,"tag":501,"props":4637,"children":4638},{"style":583},[4639],{"type":418,"value":4555},{"type":413,"tag":501,"props":4641,"children":4642},{"style":557},[4643],{"type":418,"value":4644},"$server",{"type":413,"tag":501,"props":4646,"children":4647},{"style":583},[4648],{"type":418,"value":4649}," in ",{"type":413,"tag":501,"props":4651,"children":4652},{"style":557},[4653],{"type":418,"value":4611},{"type":413,"tag":501,"props":4655,"children":4656},{"style":583},[4657],{"type":418,"value":4565},{"type":413,"tag":501,"props":4659,"children":4660},{"style":519},[4661],{"type":418,"value":794},{"type":413,"tag":501,"props":4663,"children":4665},{"class":503,"line":4664},25,[4666,4670,4675,4680,4684,4688,4693,4698,4702,4706,4710,4714,4718,4723,4728,4733],{"type":413,"tag":501,"props":4667,"children":4668},{"style":508},[4669],{"type":418,"value":4482},{"type":413,"tag":501,"props":4671,"children":4672},{"style":583},[4673],{"type":418,"value":4674}," sql",{"type":413,"tag":501,"props":4676,"children":4677},{"style":583},[4678],{"type":418,"value":4679}," server",{"type":413,"tag":501,"props":4681,"children":4682},{"style":583},[4683],{"type":418,"value":4587},{"type":413,"tag":501,"props":4685,"children":4686},{"style":583},[4687],{"type":418,"value":4592},{"type":413,"tag":501,"props":4689,"children":4690},{"style":557},[4691],{"type":418,"value":4692}," $server ",{"type":413,"tag":501,"props":4694,"children":4695},{"style":583},[4696],{"type":418,"value":4697},"--resource-group",{"type":413,"tag":501,"props":4699,"children":4700},{"style":557},[4701],{"type":418,"value":4597},{"type":413,"tag":501,"props":4703,"children":4704},{"style":583},[4705],{"type":418,"value":4602},{"type":413,"tag":501,"props":4707,"children":4708},{"style":519},[4709],{"type":418,"value":784},{"type":413,"tag":501,"props":4711,"children":4712},{"style":557},[4713],{"type":418,"value":4611},{"type":413,"tag":501,"props":4715,"children":4716},{"style":519},[4717],{"type":418,"value":580},{"type":413,"tag":501,"props":4719,"children":4720},{"style":583},[4721],{"type":418,"value":4722}," --admin-user",{"type":413,"tag":501,"props":4724,"children":4725},{"style":557},[4726],{"type":418,"value":4727}," $login ",{"type":413,"tag":501,"props":4729,"children":4730},{"style":583},[4731],{"type":418,"value":4732},"--admin-password",{"type":413,"tag":501,"props":4734,"children":4735},{"style":557},[4736],{"type":418,"value":4737}," $password\n",{"type":413,"tag":501,"props":4739,"children":4741},{"class":503,"line":4740},26,[4742],{"type":413,"tag":501,"props":4743,"children":4744},{"emptyLinePlaceholder":653},[4745],{"type":418,"value":656},{"type":413,"tag":501,"props":4747,"children":4749},{"class":503,"line":4748},27,[4750,4754,4758,4763],{"type":413,"tag":501,"props":4751,"children":4752},{"style":567},[4753],{"type":418,"value":4546},{"type":413,"tag":501,"props":4755,"children":4756},{"style":519},[4757],{"type":418,"value":784},{"type":413,"tag":501,"props":4759,"children":4760},{"style":583},[4761],{"type":418,"value":4762},"Configuring firewall...",{"type":413,"tag":501,"props":4764,"children":4765},{"style":519},[4766],{"type":418,"value":794},{"type":413,"tag":501,"props":4768,"children":4770},{"class":503,"line":4769},28,[4771,4775,4779,4783,4788,4792,4797,4801,4806,4810,4815,4820,4825,4830,4835],{"type":413,"tag":501,"props":4772,"children":4773},{"style":508},[4774],{"type":418,"value":4482},{"type":413,"tag":501,"props":4776,"children":4777},{"style":583},[4778],{"type":418,"value":4674},{"type":413,"tag":501,"props":4780,"children":4781},{"style":583},[4782],{"type":418,"value":4679},{"type":413,"tag":501,"props":4784,"children":4785},{"style":583},[4786],{"type":418,"value":4787}," firewall-rule",{"type":413,"tag":501,"props":4789,"children":4790},{"style":583},[4791],{"type":418,"value":4587},{"type":413,"tag":501,"props":4793,"children":4794},{"style":583},[4795],{"type":418,"value":4796}," --resource-group",{"type":413,"tag":501,"props":4798,"children":4799},{"style":557},[4800],{"type":418,"value":4597},{"type":413,"tag":501,"props":4802,"children":4803},{"style":583},[4804],{"type":418,"value":4805},"--server",{"type":413,"tag":501,"props":4807,"children":4808},{"style":557},[4809],{"type":418,"value":4692},{"type":413,"tag":501,"props":4811,"children":4812},{"style":583},[4813],{"type":418,"value":4814},"-n",{"type":413,"tag":501,"props":4816,"children":4817},{"style":583},[4818],{"type":418,"value":4819}," AllowYourIp",{"type":413,"tag":501,"props":4821,"children":4822},{"style":583},[4823],{"type":418,"value":4824}," --start-ip-address",{"type":413,"tag":501,"props":4826,"children":4827},{"style":557},[4828],{"type":418,"value":4829}," $startIP ",{"type":413,"tag":501,"props":4831,"children":4832},{"style":583},[4833],{"type":418,"value":4834},"--end-ip-address",{"type":413,"tag":501,"props":4836,"children":4837},{"style":557},[4838],{"type":418,"value":4839}," $endIP\n",{"type":413,"tag":501,"props":4841,"children":4843},{"class":503,"line":4842},29,[4844],{"type":413,"tag":501,"props":4845,"children":4846},{"emptyLinePlaceholder":653},[4847],{"type":418,"value":656},{"type":413,"tag":501,"props":4849,"children":4851},{"class":503,"line":4850},30,[4852,4856,4860,4864,4869,4874,4878,4882],{"type":413,"tag":501,"props":4853,"children":4854},{"style":567},[4855],{"type":418,"value":4546},{"type":413,"tag":501,"props":4857,"children":4858},{"style":519},[4859],{"type":418,"value":784},{"type":413,"tag":501,"props":4861,"children":4862},{"style":583},[4863],{"type":418,"value":4555},{"type":413,"tag":501,"props":4865,"children":4866},{"style":557},[4867],{"type":418,"value":4868},"$database",{"type":413,"tag":501,"props":4870,"children":4871},{"style":583},[4872],{"type":418,"value":4873}," on ",{"type":413,"tag":501,"props":4875,"children":4876},{"style":557},[4877],{"type":418,"value":4644},{"type":413,"tag":501,"props":4879,"children":4880},{"style":583},[4881],{"type":418,"value":4565},{"type":413,"tag":501,"props":4883,"children":4884},{"style":519},[4885],{"type":418,"value":794},{"type":413,"tag":501,"props":4887,"children":4889},{"class":503,"line":4888},31,[4890,4894,4898,4903,4907,4911,4915,4919,4923,4928,4933,4938,4943,4948,4953,4958],{"type":413,"tag":501,"props":4891,"children":4892},{"style":508},[4893],{"type":418,"value":4482},{"type":413,"tag":501,"props":4895,"children":4896},{"style":583},[4897],{"type":418,"value":4674},{"type":413,"tag":501,"props":4899,"children":4900},{"style":583},[4901],{"type":418,"value":4902}," db",{"type":413,"tag":501,"props":4904,"children":4905},{"style":583},[4906],{"type":418,"value":4587},{"type":413,"tag":501,"props":4908,"children":4909},{"style":583},[4910],{"type":418,"value":4796},{"type":413,"tag":501,"props":4912,"children":4913},{"style":557},[4914],{"type":418,"value":4597},{"type":413,"tag":501,"props":4916,"children":4917},{"style":583},[4918],{"type":418,"value":4805},{"type":413,"tag":501,"props":4920,"children":4921},{"style":557},[4922],{"type":418,"value":4692},{"type":413,"tag":501,"props":4924,"children":4925},{"style":583},[4926],{"type":418,"value":4927},"--name",{"type":413,"tag":501,"props":4929,"children":4930},{"style":557},[4931],{"type":418,"value":4932}," $database ",{"type":413,"tag":501,"props":4934,"children":4935},{"style":583},[4936],{"type":418,"value":4937},"--sample-name",{"type":413,"tag":501,"props":4939,"children":4940},{"style":583},[4941],{"type":418,"value":4942}," AdventureWorksLT",{"type":413,"tag":501,"props":4944,"children":4945},{"style":583},[4946],{"type":418,"value":4947}," --service-objective",{"type":413,"tag":501,"props":4949,"children":4950},{"style":583},[4951],{"type":418,"value":4952}," Basic",{"type":413,"tag":501,"props":4954,"children":4955},{"style":583},[4956],{"type":418,"value":4957}," --zone-redundant",{"type":413,"tag":501,"props":4959,"children":4960},{"style":519},[4961],{"type":418,"value":4962}," false\n",{"type":413,"tag":501,"props":4964,"children":4966},{"class":503,"line":4965},32,[4967],{"type":413,"tag":501,"props":4968,"children":4969},{"emptyLinePlaceholder":653},[4970],{"type":418,"value":656},{"type":413,"tag":501,"props":4972,"children":4974},{"class":503,"line":4973},33,[4975,4979,4983,4988],{"type":413,"tag":501,"props":4976,"children":4977},{"style":567},[4978],{"type":418,"value":4546},{"type":413,"tag":501,"props":4980,"children":4981},{"style":519},[4982],{"type":418,"value":784},{"type":413,"tag":501,"props":4984,"children":4985},{"style":583},[4986],{"type":418,"value":4987},"Creating AD admin in sql server...",{"type":413,"tag":501,"props":4989,"children":4990},{"style":519},[4991],{"type":418,"value":794},{"type":413,"tag":501,"props":4993,"children":4995},{"class":503,"line":4994},34,[4996,5000,5004,5008,5013,5017,5021,5025,5030,5034,5039,5044,5049],{"type":413,"tag":501,"props":4997,"children":4998},{"style":508},[4999],{"type":418,"value":4482},{"type":413,"tag":501,"props":5001,"children":5002},{"style":583},[5003],{"type":418,"value":4674},{"type":413,"tag":501,"props":5005,"children":5006},{"style":583},[5007],{"type":418,"value":4679},{"type":413,"tag":501,"props":5009,"children":5010},{"style":583},[5011],{"type":418,"value":5012}," ad-admin",{"type":413,"tag":501,"props":5014,"children":5015},{"style":583},[5016],{"type":418,"value":4587},{"type":413,"tag":501,"props":5018,"children":5019},{"style":583},[5020],{"type":418,"value":4796},{"type":413,"tag":501,"props":5022,"children":5023},{"style":557},[5024],{"type":418,"value":4597},{"type":413,"tag":501,"props":5026,"children":5027},{"style":583},[5028],{"type":418,"value":5029},"--server-name",{"type":413,"tag":501,"props":5031,"children":5032},{"style":557},[5033],{"type":418,"value":4692},{"type":413,"tag":501,"props":5035,"children":5036},{"style":583},[5037],{"type":418,"value":5038},"--display-name",{"type":413,"tag":501,"props":5040,"children":5041},{"style":583},[5042],{"type":418,"value":5043}," ADMIN",{"type":413,"tag":501,"props":5045,"children":5046},{"style":583},[5047],{"type":418,"value":5048}," --object-id",{"type":413,"tag":501,"props":5050,"children":5051},{"style":557},[5052],{"type":418,"value":5053}," $azureaduser\n",{"type":413,"tag":501,"props":5055,"children":5057},{"class":503,"line":5056},35,[5058],{"type":413,"tag":501,"props":5059,"children":5060},{"emptyLinePlaceholder":653},[5061],{"type":418,"value":656},{"type":413,"tag":501,"props":5063,"children":5065},{"class":503,"line":5064},36,[5066,5070,5074,5079,5084,5089,5093,5098,5102,5107,5111],{"type":413,"tag":501,"props":5067,"children":5068},{"style":567},[5069],{"type":418,"value":4546},{"type":413,"tag":501,"props":5071,"children":5072},{"style":519},[5073],{"type":418,"value":784},{"type":413,"tag":501,"props":5075,"children":5076},{"style":583},[5077],{"type":418,"value":5078},"Database connection string to use: ",{"type":413,"tag":501,"props":5080,"children":5081},{"style":557},[5082],{"type":418,"value":5083},"\\\"",{"type":413,"tag":501,"props":5085,"children":5086},{"style":583},[5087],{"type":418,"value":5088},"Server=",{"type":413,"tag":501,"props":5090,"children":5091},{"style":557},[5092],{"type":418,"value":4644},{"type":413,"tag":501,"props":5094,"children":5095},{"style":583},[5096],{"type":418,"value":5097},".database.windows.net; Authentication=Active Directory Default; Database=",{"type":413,"tag":501,"props":5099,"children":5100},{"style":557},[5101],{"type":418,"value":4868},{"type":413,"tag":501,"props":5103,"children":5104},{"style":583},[5105],{"type":418,"value":5106},";",{"type":413,"tag":501,"props":5108,"children":5109},{"style":557},[5110],{"type":418,"value":5083},{"type":413,"tag":501,"props":5112,"children":5113},{"style":519},[5114],{"type":418,"value":794},{"type":413,"tag":414,"props":5116,"children":5117},{},[5118],{"type":418,"value":5119},"This script should be self-explanatory if you have already played a little with Azure CLI. Basically, what it does is:",{"type":413,"tag":1523,"props":5121,"children":5122},{},[5123,5128,5140,5145,5150],{"type":413,"tag":1527,"props":5124,"children":5125},{},[5126],{"type":418,"value":5127},"create an azure SQL server",{"type":413,"tag":1527,"props":5129,"children":5130},{},[5131,5133,5138],{"type":418,"value":5132},"configure the server firewall to allow you to query it from your local IP address (if you are executing the script from cloud shell, replace ",{"type":413,"tag":443,"props":5134,"children":5136},{"className":5135},[],[5137],{"type":418,"value":4391},{"type":418,"value":5139}," variable with your local machine IP)",{"type":413,"tag":1527,"props":5141,"children":5142},{},[5143],{"type":418,"value":5144},"create an azure SQL database with already tables and data in it from the sample AdventureWorksLT",{"type":413,"tag":1527,"props":5146,"children":5147},{},[5148],{"type":418,"value":5149},"set you logged in azure ad user as the AD administrator of the database",{"type":413,"tag":1527,"props":5151,"children":5152},{},[5153],{"type":418,"value":5154},"write in the console the connection string to use in your C# code to access the database",{"type":413,"tag":414,"props":5156,"children":5157},{},[5158],{"type":418,"value":5159},"If you want to customize something do not hesitate to modify the scripts and especially variables like the resources location, the SQL server user/password, or the name of the resources. This is a bash script but if you want to execute it in PowerShell, all the Azure CLI commands should work fine, you just have to change the variables declarations as the syntax is different in PowerShell. If you don't have Azure CLI installed on your laptop you can use Azure Cloud Shell to execute this script.",{"type":413,"tag":466,"props":5161,"children":5162},{"icon":468},[5163],{"type":413,"tag":414,"props":5164,"children":5165},{},[5166,5168,5173],{"type":418,"value":5167},"If you are new to Azure CLI, you can read my article ",{"type":413,"tag":432,"props":5169,"children":5171},{"href":458,"rel":5170},[436],[5172],{"type":418,"value":15},{"type":418,"value":564},{"type":413,"tag":1556,"props":5175,"children":5177},{"id":5176},"querying-the-database-from-a-minima-api-in-c",[5178],{"type":418,"value":5179},"Querying the database from a minima API in C#",{"type":413,"tag":414,"props":5181,"children":5182},{},[5183,5185,5192],{"type":418,"value":5184},"Usually, I like to create a console application (with the ",{"type":413,"tag":432,"props":5186,"children":5189},{"href":5187,"rel":5188},"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-5.0&tabs=visual-studio#worker-service-template",[436],[5190],{"type":418,"value":5191},"worker service template",{"type":418,"value":5193}," for instance) for my samples, yet this time I decided to try the new minimal APIs from .NET 6 (currently in preview).",{"type":413,"tag":414,"props":5195,"children":5196},{},[5197,5199,5205],{"type":418,"value":5198},"Minimal APIs would probably deserve an entire blog post, but let's just say a minimal API in .NET 6 allow you to build a small HTTP API with less ceremony than a classic controller-based API. As all the code can be written in a ",{"type":413,"tag":443,"props":5200,"children":5202},{"className":5201},[],[5203],{"type":418,"value":5204},"Program.cs",{"type":418,"value":5206}," file, so it's very convenient when you want to quickly build a web application without too much complexity (especially if you are new to ASP.NET Core) or if you are developing a small microservice.",{"type":413,"tag":492,"props":5208,"children":5210},{"className":494,"code":5209,"language":326,"meta":401,"style":401},"using Dapper;\nusing Microsoft.Data.SqlClient;\n\nvar builder = WebApplication.CreateBuilder(args);\nvar app = builder.Build();\n\nif (app.Environment.IsDevelopment())\n{\n    app.UseDeveloperExceptionPage();\n}\n\napp.MapGet(\"/\", async () =>\n{\n    using var connection = new SqlConnection(\"Server=server-testingmsi28497.database.windows.net; Authentication=Active Directory Default; Database=database-testingmsi28497;\");\n    var products = await connection.QueryAsync\u003CProduct>(\"SELECT TOP 10 ProductID, Name from [SalesLT].[Product]\");\n    return products;\n});\n\napp.Run();\n\npublic record Product(int ProductID, string Name);\n",[5211],{"type":413,"tag":443,"props":5212,"children":5213},{"__ignoreMap":401},[5214,5230,5263,5270,5313,5346,5353,5393,5400,5421,5428,5435,5487,5494,5543,5608,5623,5630,5637,5657,5664],{"type":413,"tag":501,"props":5215,"children":5216},{"class":503,"line":504},[5217,5221,5226],{"type":413,"tag":501,"props":5218,"children":5219},{"style":1402},[5220],{"type":418,"value":3534},{"type":413,"tag":501,"props":5222,"children":5223},{"style":557},[5224],{"type":418,"value":5225}," Dapper",{"type":413,"tag":501,"props":5227,"children":5228},{"style":519},[5229],{"type":418,"value":1430},{"type":413,"tag":501,"props":5231,"children":5232},{"class":503,"line":540},[5233,5237,5242,5246,5251,5255,5259],{"type":413,"tag":501,"props":5234,"children":5235},{"style":1402},[5236],{"type":418,"value":3534},{"type":413,"tag":501,"props":5238,"children":5239},{"style":557},[5240],{"type":418,"value":5241}," Microsoft",{"type":413,"tag":501,"props":5243,"children":5244},{"style":519},[5245],{"type":418,"value":564},{"type":413,"tag":501,"props":5247,"children":5248},{"style":557},[5249],{"type":418,"value":5250},"Data",{"type":413,"tag":501,"props":5252,"children":5253},{"style":519},[5254],{"type":418,"value":564},{"type":413,"tag":501,"props":5256,"children":5257},{"style":557},[5258],{"type":418,"value":3971},{"type":413,"tag":501,"props":5260,"children":5261},{"style":519},[5262],{"type":418,"value":1430},{"type":413,"tag":501,"props":5264,"children":5265},{"class":503,"line":598},[5266],{"type":413,"tag":501,"props":5267,"children":5268},{"emptyLinePlaceholder":653},[5269],{"type":418,"value":656},{"type":413,"tag":501,"props":5271,"children":5272},{"class":503,"line":649},[5273,5277,5282,5286,5291,5295,5300,5304,5309],{"type":413,"tag":501,"props":5274,"children":5275},{"style":508},[5276],{"type":418,"value":511},{"type":413,"tag":501,"props":5278,"children":5279},{"style":508},[5280],{"type":418,"value":5281}," builder",{"type":413,"tag":501,"props":5283,"children":5284},{"style":519},[5285],{"type":418,"value":522},{"type":413,"tag":501,"props":5287,"children":5288},{"style":557},[5289],{"type":418,"value":5290}," WebApplication",{"type":413,"tag":501,"props":5292,"children":5293},{"style":519},[5294],{"type":418,"value":564},{"type":413,"tag":501,"props":5296,"children":5297},{"style":567},[5298],{"type":418,"value":5299},"CreateBuilder",{"type":413,"tag":501,"props":5301,"children":5302},{"style":519},[5303],{"type":418,"value":575},{"type":413,"tag":501,"props":5305,"children":5306},{"style":557},[5307],{"type":418,"value":5308},"args",{"type":413,"tag":501,"props":5310,"children":5311},{"style":519},[5312],{"type":418,"value":595},{"type":413,"tag":501,"props":5314,"children":5315},{"class":503,"line":659},[5316,5320,5325,5329,5333,5337,5342],{"type":413,"tag":501,"props":5317,"children":5318},{"style":508},[5319],{"type":418,"value":511},{"type":413,"tag":501,"props":5321,"children":5322},{"style":508},[5323],{"type":418,"value":5324}," app",{"type":413,"tag":501,"props":5326,"children":5327},{"style":519},[5328],{"type":418,"value":522},{"type":413,"tag":501,"props":5330,"children":5331},{"style":557},[5332],{"type":418,"value":5281},{"type":413,"tag":501,"props":5334,"children":5335},{"style":519},[5336],{"type":418,"value":564},{"type":413,"tag":501,"props":5338,"children":5339},{"style":567},[5340],{"type":418,"value":5341},"Build",{"type":413,"tag":501,"props":5343,"children":5344},{"style":519},[5345],{"type":418,"value":537},{"type":413,"tag":501,"props":5347,"children":5348},{"class":503,"line":716},[5349],{"type":413,"tag":501,"props":5350,"children":5351},{"emptyLinePlaceholder":653},[5352],{"type":418,"value":656},{"type":413,"tag":501,"props":5354,"children":5355},{"class":503,"line":725},[5356,5361,5365,5370,5374,5379,5383,5388],{"type":413,"tag":501,"props":5357,"children":5358},{"style":1812},[5359],{"type":418,"value":5360},"if",{"type":413,"tag":501,"props":5362,"children":5363},{"style":519},[5364],{"type":418,"value":3539},{"type":413,"tag":501,"props":5366,"children":5367},{"style":557},[5368],{"type":418,"value":5369},"app",{"type":413,"tag":501,"props":5371,"children":5372},{"style":519},[5373],{"type":418,"value":564},{"type":413,"tag":501,"props":5375,"children":5376},{"style":557},[5377],{"type":418,"value":5378},"Environment",{"type":413,"tag":501,"props":5380,"children":5381},{"style":519},[5382],{"type":418,"value":564},{"type":413,"tag":501,"props":5384,"children":5385},{"style":567},[5386],{"type":418,"value":5387},"IsDevelopment",{"type":413,"tag":501,"props":5389,"children":5390},{"style":519},[5391],{"type":418,"value":5392},"())\n",{"type":413,"tag":501,"props":5394,"children":5395},{"class":503,"line":748},[5396],{"type":413,"tag":501,"props":5397,"children":5398},{"style":519},[5399],{"type":418,"value":722},{"type":413,"tag":501,"props":5401,"children":5402},{"class":503,"line":769},[5403,5408,5412,5417],{"type":413,"tag":501,"props":5404,"children":5405},{"style":557},[5406],{"type":418,"value":5407},"    app",{"type":413,"tag":501,"props":5409,"children":5410},{"style":519},[5411],{"type":418,"value":564},{"type":413,"tag":501,"props":5413,"children":5414},{"style":567},[5415],{"type":418,"value":5416},"UseDeveloperExceptionPage",{"type":413,"tag":501,"props":5418,"children":5419},{"style":519},[5420],{"type":418,"value":537},{"type":413,"tag":501,"props":5422,"children":5423},{"class":503,"line":797},[5424],{"type":413,"tag":501,"props":5425,"children":5426},{"style":519},[5427],{"type":418,"value":2530},{"type":413,"tag":501,"props":5429,"children":5430},{"class":503,"line":1145},[5431],{"type":413,"tag":501,"props":5432,"children":5433},{"emptyLinePlaceholder":653},[5434],{"type":418,"value":656},{"type":413,"tag":501,"props":5436,"children":5437},{"class":503,"line":1154},[5438,5442,5446,5451,5455,5459,5464,5468,5472,5478,5483],{"type":413,"tag":501,"props":5439,"children":5440},{"style":557},[5441],{"type":418,"value":5369},{"type":413,"tag":501,"props":5443,"children":5444},{"style":519},[5445],{"type":418,"value":564},{"type":413,"tag":501,"props":5447,"children":5448},{"style":567},[5449],{"type":418,"value":5450},"MapGet",{"type":413,"tag":501,"props":5452,"children":5453},{"style":519},[5454],{"type":418,"value":575},{"type":413,"tag":501,"props":5456,"children":5457},{"style":519},[5458],{"type":418,"value":580},{"type":413,"tag":501,"props":5460,"children":5461},{"style":583},[5462],{"type":418,"value":5463},"/",{"type":413,"tag":501,"props":5465,"children":5466},{"style":519},[5467],{"type":418,"value":580},{"type":413,"tag":501,"props":5469,"children":5470},{"style":519},[5471],{"type":418,"value":704},{"type":413,"tag":501,"props":5473,"children":5475},{"style":5474},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[5476],{"type":418,"value":5477}," async",{"type":413,"tag":501,"props":5479,"children":5480},{"style":519},[5481],{"type":418,"value":5482}," ()",{"type":413,"tag":501,"props":5484,"children":5485},{"style":519},[5486],{"type":418,"value":1753},{"type":413,"tag":501,"props":5488,"children":5489},{"class":503,"line":4376},[5490],{"type":413,"tag":501,"props":5491,"children":5492},{"style":519},[5493],{"type":418,"value":722},{"type":413,"tag":501,"props":5495,"children":5496},{"class":503,"line":4385},[5497,5502,5506,5510,5514,5518,5522,5526,5530,5535,5539],{"type":413,"tag":501,"props":5498,"children":5499},{"style":1812},[5500],{"type":418,"value":5501},"    using",{"type":413,"tag":501,"props":5503,"children":5504},{"style":508},[5505],{"type":418,"value":3788},{"type":413,"tag":501,"props":5507,"children":5508},{"style":508},[5509],{"type":418,"value":3587},{"type":413,"tag":501,"props":5511,"children":5512},{"style":519},[5513],{"type":418,"value":522},{"type":413,"tag":501,"props":5515,"children":5516},{"style":519},[5517],{"type":418,"value":527},{"type":413,"tag":501,"props":5519,"children":5520},{"style":508},[5521],{"type":418,"value":3561},{"type":413,"tag":501,"props":5523,"children":5524},{"style":519},[5525],{"type":418,"value":575},{"type":413,"tag":501,"props":5527,"children":5528},{"style":519},[5529],{"type":418,"value":580},{"type":413,"tag":501,"props":5531,"children":5532},{"style":583},[5533],{"type":418,"value":5534},"Server=server-testingmsi28497.database.windows.net; Authentication=Active Directory Default; Database=database-testingmsi28497;",{"type":413,"tag":501,"props":5536,"children":5537},{"style":519},[5538],{"type":418,"value":580},{"type":413,"tag":501,"props":5540,"children":5541},{"style":519},[5542],{"type":418,"value":595},{"type":413,"tag":501,"props":5544,"children":5545},{"class":503,"line":4423},[5546,5551,5556,5560,5564,5568,5572,5577,5581,5586,5591,5595,5600,5604],{"type":413,"tag":501,"props":5547,"children":5548},{"style":508},[5549],{"type":418,"value":5550},"    var",{"type":413,"tag":501,"props":5552,"children":5553},{"style":508},[5554],{"type":418,"value":5555}," products",{"type":413,"tag":501,"props":5557,"children":5558},{"style":519},[5559],{"type":418,"value":522},{"type":413,"tag":501,"props":5561,"children":5562},{"style":519},[5563],{"type":418,"value":3713},{"type":413,"tag":501,"props":5565,"children":5566},{"style":557},[5567],{"type":418,"value":3587},{"type":413,"tag":501,"props":5569,"children":5570},{"style":519},[5571],{"type":418,"value":564},{"type":413,"tag":501,"props":5573,"children":5574},{"style":567},[5575],{"type":418,"value":5576},"QueryAsync",{"type":413,"tag":501,"props":5578,"children":5579},{"style":519},[5580],{"type":418,"value":2497},{"type":413,"tag":501,"props":5582,"children":5583},{"style":508},[5584],{"type":418,"value":5585},"Product",{"type":413,"tag":501,"props":5587,"children":5588},{"style":519},[5589],{"type":418,"value":5590},">(",{"type":413,"tag":501,"props":5592,"children":5593},{"style":519},[5594],{"type":418,"value":580},{"type":413,"tag":501,"props":5596,"children":5597},{"style":583},[5598],{"type":418,"value":5599},"SELECT TOP 10 ProductID, Name from [SalesLT].[Product]",{"type":413,"tag":501,"props":5601,"children":5602},{"style":519},[5603],{"type":418,"value":580},{"type":413,"tag":501,"props":5605,"children":5606},{"style":519},[5607],{"type":418,"value":595},{"type":413,"tag":501,"props":5609,"children":5610},{"class":503,"line":4441},[5611,5615,5619],{"type":413,"tag":501,"props":5612,"children":5613},{"style":1812},[5614],{"type":418,"value":1815},{"type":413,"tag":501,"props":5616,"children":5617},{"style":557},[5618],{"type":418,"value":5555},{"type":413,"tag":501,"props":5620,"children":5621},{"style":519},[5622],{"type":418,"value":1430},{"type":413,"tag":501,"props":5624,"children":5625},{"class":503,"line":4449},[5626],{"type":413,"tag":501,"props":5627,"children":5628},{"style":519},[5629],{"type":418,"value":803},{"type":413,"tag":501,"props":5631,"children":5632},{"class":503,"line":4458},[5633],{"type":413,"tag":501,"props":5634,"children":5635},{"emptyLinePlaceholder":653},[5636],{"type":418,"value":656},{"type":413,"tag":501,"props":5638,"children":5639},{"class":503,"line":4467},[5640,5644,5648,5653],{"type":413,"tag":501,"props":5641,"children":5642},{"style":557},[5643],{"type":418,"value":5369},{"type":413,"tag":501,"props":5645,"children":5646},{"style":519},[5647],{"type":418,"value":564},{"type":413,"tag":501,"props":5649,"children":5650},{"style":567},[5651],{"type":418,"value":5652},"Run",{"type":413,"tag":501,"props":5654,"children":5655},{"style":519},[5656],{"type":418,"value":537},{"type":413,"tag":501,"props":5658,"children":5659},{"class":503,"line":4532},[5660],{"type":413,"tag":501,"props":5661,"children":5662},{"emptyLinePlaceholder":653},[5663],{"type":418,"value":656},{"type":413,"tag":501,"props":5665,"children":5666},{"class":503,"line":4540},[5667,5672,5677,5682,5687,5692,5696,5700,5705],{"type":413,"tag":501,"props":5668,"children":5669},{"style":5474},[5670],{"type":418,"value":5671},"public",{"type":413,"tag":501,"props":5673,"children":5674},{"style":508},[5675],{"type":418,"value":5676}," record",{"type":413,"tag":501,"props":5678,"children":5679},{"style":508},[5680],{"type":418,"value":5681}," Product",{"type":413,"tag":501,"props":5683,"children":5684},{"style":519},[5685],{"type":418,"value":5686},"(int",{"type":413,"tag":501,"props":5688,"children":5689},{"style":508},[5690],{"type":418,"value":5691}," ProductID",{"type":413,"tag":501,"props":5693,"children":5694},{"style":519},[5695],{"type":418,"value":704},{"type":413,"tag":501,"props":5697,"children":5698},{"style":519},[5699],{"type":418,"value":3749},{"type":413,"tag":501,"props":5701,"children":5702},{"style":508},[5703],{"type":418,"value":5704}," Name",{"type":413,"tag":501,"props":5706,"children":5707},{"style":519},[5708],{"type":418,"value":595},{"type":413,"tag":414,"props":5710,"children":5711},{},[5712],{"type":418,"value":5713},"As you can see this code is only 26 lines long:",{"type":413,"tag":1523,"props":5715,"children":5716},{},[5717,5730,5742,5754],{"type":413,"tag":1527,"props":5718,"children":5719},{},[5720,5722,5728],{"type":418,"value":5721},"there is only one route, that returns the Product identifiers and names from the table ",{"type":413,"tag":443,"props":5723,"children":5725},{"className":5724},[],[5726],{"type":418,"value":5727},"[SalesLT].[Product]",{"type":418,"value":5729}," of the database created with the previous Azure CLI script",{"type":413,"tag":1527,"props":5731,"children":5732},{},[5733,5735,5740],{"type":418,"value":5734},"the SQL query is done by using the micro ORM ",{"type":413,"tag":432,"props":5736,"children":5738},{"href":1684,"rel":5737},[436],[5739],{"type":418,"value":1688},{"type":418,"value":5741}," which simplifies the boilerplate code to query an SQL database while keeping performance",{"type":413,"tag":1527,"props":5743,"children":5744},{},[5745,5747,5752],{"type":418,"value":5746},"the result of the SQL query is mapped to a record class ",{"type":413,"tag":443,"props":5748,"children":5750},{"className":5749},[],[5751],{"type":418,"value":5585},{"type":418,"value":5753}," which is declared in one line",{"type":413,"tag":1527,"props":5755,"children":5756},{},[5757,5759,5764,5766,5771],{"type":418,"value":5758},"the code uses ",{"type":413,"tag":443,"props":5760,"children":5762},{"className":5761},[],[5763],{"type":418,"value":448},{"type":418,"value":5765}," v3.0.0 with the ",{"type":413,"tag":443,"props":5767,"children":5769},{"className":5768},[],[5770],{"type":418,"value":3418},{"type":418,"value":3946},{"type":413,"tag":414,"props":5773,"children":5774},{},[5775],{"type":413,"tag":1580,"props":5776,"children":5780},{"alt":5777,"className":5778,"src":5779},"C# code querying an SQL Database using Active Directory Default authentication mode.",[1584,1585],"/posts/images/sqlclient_minapi_1.png",[],{"type":413,"tag":466,"props":5782,"children":5783},{"icon":468},[5784],{"type":413,"tag":414,"props":5785,"children":5786},{},[5787,5789,5795],{"type":418,"value":5788},"To keep things simple, I am connecting to the database with the Azure AD account which is an admin of the SQL server. But I could also have assigned a role with lower permissions to my account, see ",{"type":413,"tag":432,"props":5790,"children":5793},{"href":5791,"rel":5792},"https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi#grant-permissions-to-managed-identity",[436],[5794],{"type":418,"value":4073},{"type":418,"value":5796}," for more information on how to do that.",{"type":413,"tag":420,"props":5798,"children":5800},{"id":5799},"to-conclude",[5801],{"type":418,"value":5802},"To conclude",{"type":413,"tag":414,"props":5804,"children":5805},{},[5806,5808,5814],{"type":418,"value":5807},"While building an application interacting with Azure we often neglect to use mechanisms like Azure AD authentication that remove the need for secrets. But as we have seen in this article some libraries like ",{"type":413,"tag":443,"props":5809,"children":5811},{"className":5810},[],[5812],{"type":418,"value":5813},"Microsoft.Data.Sql.Client",{"type":418,"value":5815}," or the Azure SDKs allow us to do that quite easily. I love how connecting to an Azure SQL Database in C# is becoming more simple and more secure at the same time.",{"type":413,"tag":3363,"props":5817,"children":5818},{},[5819],{"type":418,"value":3367},{"title":401,"searchDepth":540,"depth":540,"links":5821},[5822,5823,5824,5826,5830],{"id":3451,"depth":540,"text":3454},{"id":3647,"depth":540,"text":3650},{"id":3936,"depth":540,"text":5825},"Here comes Active Directory Default authentication mode",{"id":4077,"depth":540,"text":4080,"children":5827},[5828,5829],{"id":4088,"depth":598,"text":4091},{"id":5176,"depth":598,"text":5179},{"id":5799,"depth":540,"text":5802},"content:1.posts:20.sqlclient-active-directory-authent.md","1.posts/20.sqlclient-active-directory-authent.md",1716749600714]