[{"data":1,"prerenderedAt":6528},["Reactive",2],{"navigation":3,"aAII9Cz3yR":204,"tags-Azure Key Vault":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,1485,4094,6133],{"_path":124,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":123,"description":402,"lead":403,"date":404,"image":405,"badge":407,"tags":409,"body":410,"_type":1480,"_id":1481,"_source":1482,"_file":1483,"_extension":1484},"posts",false,"","When using some API Clients (like REST Client or the HTTP Client of JetBrains' IDEs), environment variables are stored in JSON files that can contain secrets. To share these files within a team, developers tend to send them by email or by messaging applications, which is not very convenient nor secure 🔐. I thought it would be a good idea to store these secrets directly in an Azure Key Vault and automate the generation of a JSON file containing the secrets using Azure CLI and Nushell.","Playing with Azure CLI and Nushell to generate a secret environment file to send HTTP requests","2022-08-01T00:00:00.000Z",{"src":406},"/images/padlock_1.jpg",{"label":408},"Tooling",[206,213,243,225,260],{"type":411,"children":412,"toc":1474},"root",[413,458,465,502,554,605,617,622,645,651,656,665,670,676,697,710,719,731,916,921,930,935,944,957,966,982,994,1003,1023,1032,1045,1054,1083,1088,1097,1110,1118,1123,1132,1144,1153,1165,1170,1438,1444,1449,1463,1468],{"type":414,"tag":415,"props":416,"children":417},"element","p",{},[418,421,430,432,439,441,447,449,456],{"type":419,"value":420},"text","When using some API Clients (like ",{"type":414,"tag":422,"props":423,"children":427},"a",{"href":424,"rel":425},"https://marketplace.visualstudio.com/items?itemName=humao.rest-client",[426],"nofollow",[428],{"type":419,"value":429},"REST Client",{"type":419,"value":431}," or the ",{"type":414,"tag":422,"props":433,"children":436},{"href":434,"rel":435},"https://www.jetbrains.com/help/rider/Http_client_in__product__code_editor.html",[426],[437],{"type":419,"value":438},"HTTP Client of JetBrains' IDEs",{"type":419,"value":440},"), environment variables are stored in JSON files that can contain secrets. To share these files within a team, developers tend to send them by email or by messaging applications, which is not very convenient nor secure 🔐. I thought it would be a good idea to store these secrets directly in an Azure Key Vault and automate the generation of a JSON file containing the secrets using ",{"type":414,"tag":422,"props":442,"children":445},{"href":443,"rel":444},"https://docs.microsoft.com/en-us/cli/azure/",[426],[446],{"type":419,"value":225},{"type":419,"value":448}," and ",{"type":414,"tag":422,"props":450,"children":453},{"href":451,"rel":452},"https://www.nushell.sh/",[426],[454],{"type":419,"value":455},"Nushell",{"type":419,"value":457},".",{"type":414,"tag":459,"props":460,"children":462},"h2",{"id":461},"the-problem-keep-secrets-secure-while-making-http-requests",[463],{"type":419,"value":464},"The problem: keep secrets secure while making HTTP requests",{"type":414,"tag":415,"props":466,"children":467},{},[468,470,476,478,484,486,492,494,500],{"type":419,"value":469},"If you have read my article \"",{"type":414,"tag":422,"props":471,"children":474},{"href":472,"rel":473},"https://www.techwatching.dev/posts/testing-your-api-with-rest-client",[426],[475],{"type":419,"value":9},{"type":419,"value":477},"\", you know I am a big fan of using the vscode extension ",{"type":414,"tag":479,"props":480,"children":482},"code",{"className":481},[],[483],{"type":419,"value":429},{"type":419,"value":485}," to make HTTP requests instead of using GUI tools like Postman. With REST Client, you write your HTTP requests using the standard RFC 2616 in ",{"type":414,"tag":479,"props":487,"children":489},{"className":488},[],[490],{"type":419,"value":491},".http",{"type":419,"value":493}," or ",{"type":414,"tag":479,"props":495,"children":497},{"className":496},[],[498],{"type":419,"value":499},".rest",{"type":419,"value":501}," files and commit them to your git repository. You can define environments and their associated variables in the workspace settings file of vscode (you can also store them in the user settings file but I don't recommend it as they would apply to every vscode workspace). If you have some secrets among your environment variables (like an API key for instance), you obviously can't commit this settings file (you should never commit secrets to a git repository). So sharing among your developer team the environment variables needed to run the requests can be difficult.",{"type":414,"tag":503,"props":504,"children":507},"pre",{"className":505,"code":506,"language":212,"meta":401,"style":401},"language-http shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","### Get Luke Skywalker\nGET https://swapi.co/api/people/?search=Luke HTTP/1.1\n",[508],{"type":414,"tag":479,"props":509,"children":510},{"__ignoreMap":401},[511,523],{"type":414,"tag":512,"props":513,"children":516},"span",{"class":514,"line":515},"line",1,[517],{"type":414,"tag":512,"props":518,"children":520},{"style":519},"--shiki-light:#90A4AE;--shiki-default:#546E7A;--shiki-dark:#676E95;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[521],{"type":419,"value":522},"### Get Luke Skywalker\n",{"type":414,"tag":512,"props":524,"children":526},{"class":514,"line":525},2,[527,533,539,544,549],{"type":414,"tag":512,"props":528,"children":530},{"style":529},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[531],{"type":419,"value":532},"GET",{"type":414,"tag":512,"props":534,"children":536},{"style":535},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[537],{"type":419,"value":538}," https://swapi.co/api/people/?search=Luke ",{"type":414,"tag":512,"props":540,"children":542},{"style":541},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[543],{"type":419,"value":213},{"type":414,"tag":512,"props":545,"children":546},{"style":535},[547],{"type":419,"value":548},"/",{"type":414,"tag":512,"props":550,"children":551},{"style":541},[552],{"type":419,"value":553},"1.1\n",{"type":414,"tag":415,"props":555,"children":556},{},[557,559,566,568,574,576,581,582,587,589,595,597,603],{"type":419,"value":558},"I have been using recently the IDE ",{"type":414,"tag":422,"props":560,"children":563},{"href":561,"rel":562},"https://www.jetbrains.com/fr-fr/rider/",[426],[564],{"type":419,"value":565},"Rider",{"type":419,"value":567},", which has (like all the other JetBrains' IDEs) an integrated ",{"type":414,"tag":422,"props":569,"children":571},{"href":434,"rel":570},[426],[572],{"type":419,"value":573},"HTTP Client",{"type":419,"value":575},". It's very similar to REST Client (same syntax for the requests that are written in ",{"type":414,"tag":479,"props":577,"children":579},{"className":578},[],[580],{"type":419,"value":491},{"type":419,"value":493},{"type":414,"tag":479,"props":583,"children":585},{"className":584},[],[586],{"type":419,"value":499},{"type":419,"value":588}," files) with some extra features. With this HTTP Client, environment variables are stored in a public JSON environment file ",{"type":414,"tag":479,"props":590,"children":592},{"className":591},[],[593],{"type":419,"value":594},"http-client.env.json",{"type":419,"value":596}," that can be committed. However, secrets can be stored in a private JSON environment file ",{"type":414,"tag":479,"props":598,"children":600},{"className":599},[],[601],{"type":419,"value":602},"http-client.private.env.json",{"type":419,"value":604}," that will not be committed and whose values will override the values in the public file. It's well thought out, yet we still have the problem of sharing with our team the private file containing the secrets.",{"type":414,"tag":415,"props":606,"children":607},{},[608],{"type":414,"tag":609,"props":610,"children":616},"img",{"alt":611,"className":612,"src":615},"HTTP file, HTTP environment file, and HTTP private environment opnened file in Rider.",[613,614],"rounded-lg","mx-auto","/posts/images/httpclientssecrets_rider_1.png",[],{"type":414,"tag":415,"props":618,"children":619},{},[620],{"type":419,"value":621},"When someone joins the team or new environment variables have been added, the developer in the team that has the latest version of the environment file usually share it by sending it by email or private message in Microsoft Teams, or Slack... to those who need it. This is not very convenient and this is not a good practice because you don't want secrets floating around. So what can we do about that?",{"type":414,"tag":623,"props":624,"children":626},"callout",{"icon":625},"i-heroicons-chat-bubble-left-20-solid",[627],{"type":414,"tag":415,"props":628,"children":629},{},[630,632,637,638,643],{"type":419,"value":631},"To be honest, even if sharing secrets like that bothered me a bit, I only decided to think of a solution when a friend pointed out to me that the big challenge with tools like ",{"type":414,"tag":479,"props":633,"children":635},{"className":634},[],[636],{"type":419,"value":429},{"type":419,"value":493},{"type":414,"tag":479,"props":639,"children":641},{"className":640},[],[642],{"type":419,"value":573},{"type":419,"value":644}," from JetBrains was managing secrets.",{"type":414,"tag":459,"props":646,"children":648},{"id":647},"the-solution-use-azure-key-vault-and-scripting",[649],{"type":419,"value":650},"The solution: use Azure Key Vault and scripting",{"type":414,"tag":415,"props":652,"children":653},{},[654],{"type":419,"value":655},"The solution is not complicated. I asked myself: where do I usually store secrets? The answer is \"a vault\". Whether it is Azure Key Vault, AWS Secret Manager, Google Cloud Secret Manager, or HashiCorp Vault it does not matter, secrets have to be stored somewhere safe, and it's precisely the purpose of a vault 🔒. I use Azure Key Vault when developing applications so that's what I am going to use as well for secrets needed for sending HTTP requests. If I want my team to be able to retrieve the secrets I just have to ensure everyone has access to the Key Vault.",{"type":414,"tag":623,"props":657,"children":659},{"icon":658},"i-heroicons-light-bulb",[660],{"type":414,"tag":415,"props":661,"children":662},{},[663],{"type":419,"value":664},"By the way, I like to create an Azure AD Group for my team so that all the permissions given in Azure (for the project the team is working on) are assigned to this group instead of to each developer. When someone joins or leaves the team, we then can simply add him to the group or remove him from it.",{"type":414,"tag":415,"props":666,"children":667},{},[668],{"type":419,"value":669},"If the secrets are stored in an Azure Key Vault, we can let each developer retrieve the secrets from the vault and put them in their private environment file. But honestly, it's not convenient, especially with many secrets. A better solution is to make a script that automatically retrieves the secrets and generates the JSON file. That way the git repository will contain the HTTP requests, the public environment file, and a script to generate the private environment file so that any new joiner will have everything he needs to get started and run the requests.",{"type":414,"tag":459,"props":671,"children":673},{"id":672},"lets-script-that-with-azure-cli-and-nushell",[674],{"type":419,"value":675},"Let's script that with Azure CLI and Nushell!",{"type":414,"tag":415,"props":677,"children":678},{},[679,681,687,689,695],{"type":419,"value":680},"I have chosen to script that using Azure CLI and Nushell because these are 2 tools I like and I am confident the resulting script will be concise and not too difficult to write. If you are not familiar with Azure CLI, you can check my article \"",{"type":414,"tag":422,"props":682,"children":685},{"href":683,"rel":684},"https://www.techwatching.dev/posts/welcome-azure-cli",[426],[686],{"type":419,"value":15},{"type":419,"value":688},"\". If you don't know Nushell you can check its ",{"type":414,"tag":422,"props":690,"children":692},{"href":451,"rel":691},[426],[693],{"type":419,"value":694},"website",{"type":419,"value":696}," or just continue reading this article to see how nice this shell is.",{"type":414,"tag":415,"props":698,"children":699},{},[700,702,708],{"type":419,"value":701},"I have already created an Azure Key Vault named ",{"type":414,"tag":479,"props":703,"children":705},{"className":704},[],[706],{"type":419,"value":707},"httpclient-vault",{"type":419,"value":709}," and set 3 secrets in it.",{"type":414,"tag":415,"props":711,"children":712},{},[713],{"type":414,"tag":609,"props":714,"children":718},{"alt":715,"className":716,"src":717},"The Secrets view of an Azure Key Vault resource in Azure Portal",[613,614],"/posts/images/httpclientssecrets_keyvault_1.png",[],{"type":414,"tag":415,"props":720,"children":721},{},[722,724,729],{"type":419,"value":723},"What I am trying to achieve is to produce the following file ",{"type":414,"tag":479,"props":725,"children":727},{"className":726},[],[728],{"type":419,"value":602},{"type":419,"value":730},":",{"type":414,"tag":503,"props":732,"children":736},{"className":733,"code":734,"language":735,"meta":401,"style":401},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"development\":\n  {\n    \"ApiKey\": \"12345678\",\n    \"Username\": \"admin\",\n    \"UserPassword\": \"Password\"\n  }\n}\n","json",[737],{"type":414,"tag":479,"props":738,"children":739},{"__ignoreMap":401},[740,749,773,782,825,863,898,907],{"type":414,"tag":512,"props":741,"children":742},{"class":514,"line":515},[743],{"type":414,"tag":512,"props":744,"children":746},{"style":745},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[747],{"type":419,"value":748},"{\n",{"type":414,"tag":512,"props":750,"children":751},{"class":514,"line":525},[752,757,763,768],{"type":414,"tag":512,"props":753,"children":754},{"style":745},[755],{"type":419,"value":756},"  \"",{"type":414,"tag":512,"props":758,"children":760},{"style":759},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[761],{"type":419,"value":762},"development",{"type":414,"tag":512,"props":764,"children":765},{"style":745},[766],{"type":419,"value":767},"\"",{"type":414,"tag":512,"props":769,"children":770},{"style":745},[771],{"type":419,"value":772},":\n",{"type":414,"tag":512,"props":774,"children":776},{"class":514,"line":775},3,[777],{"type":414,"tag":512,"props":778,"children":779},{"style":745},[780],{"type":419,"value":781},"  {\n",{"type":414,"tag":512,"props":783,"children":785},{"class":514,"line":784},4,[786,791,797,801,805,810,816,820],{"type":414,"tag":512,"props":787,"children":788},{"style":745},[789],{"type":419,"value":790},"    \"",{"type":414,"tag":512,"props":792,"children":794},{"style":793},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[795],{"type":419,"value":796},"ApiKey",{"type":414,"tag":512,"props":798,"children":799},{"style":745},[800],{"type":419,"value":767},{"type":414,"tag":512,"props":802,"children":803},{"style":745},[804],{"type":419,"value":730},{"type":414,"tag":512,"props":806,"children":807},{"style":745},[808],{"type":419,"value":809}," \"",{"type":414,"tag":512,"props":811,"children":813},{"style":812},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[814],{"type":419,"value":815},"12345678",{"type":414,"tag":512,"props":817,"children":818},{"style":745},[819],{"type":419,"value":767},{"type":414,"tag":512,"props":821,"children":822},{"style":745},[823],{"type":419,"value":824},",\n",{"type":414,"tag":512,"props":826,"children":828},{"class":514,"line":827},5,[829,833,838,842,846,850,855,859],{"type":414,"tag":512,"props":830,"children":831},{"style":745},[832],{"type":419,"value":790},{"type":414,"tag":512,"props":834,"children":835},{"style":793},[836],{"type":419,"value":837},"Username",{"type":414,"tag":512,"props":839,"children":840},{"style":745},[841],{"type":419,"value":767},{"type":414,"tag":512,"props":843,"children":844},{"style":745},[845],{"type":419,"value":730},{"type":414,"tag":512,"props":847,"children":848},{"style":745},[849],{"type":419,"value":809},{"type":414,"tag":512,"props":851,"children":852},{"style":812},[853],{"type":419,"value":854},"admin",{"type":414,"tag":512,"props":856,"children":857},{"style":745},[858],{"type":419,"value":767},{"type":414,"tag":512,"props":860,"children":861},{"style":745},[862],{"type":419,"value":824},{"type":414,"tag":512,"props":864,"children":866},{"class":514,"line":865},6,[867,871,876,880,884,888,893],{"type":414,"tag":512,"props":868,"children":869},{"style":745},[870],{"type":419,"value":790},{"type":414,"tag":512,"props":872,"children":873},{"style":793},[874],{"type":419,"value":875},"UserPassword",{"type":414,"tag":512,"props":877,"children":878},{"style":745},[879],{"type":419,"value":767},{"type":414,"tag":512,"props":881,"children":882},{"style":745},[883],{"type":419,"value":730},{"type":414,"tag":512,"props":885,"children":886},{"style":745},[887],{"type":419,"value":809},{"type":414,"tag":512,"props":889,"children":890},{"style":812},[891],{"type":419,"value":892},"Password",{"type":414,"tag":512,"props":894,"children":895},{"style":745},[896],{"type":419,"value":897},"\"\n",{"type":414,"tag":512,"props":899,"children":901},{"class":514,"line":900},7,[902],{"type":414,"tag":512,"props":903,"children":904},{"style":745},[905],{"type":419,"value":906},"  }\n",{"type":414,"tag":512,"props":908,"children":910},{"class":514,"line":909},8,[911],{"type":414,"tag":512,"props":912,"children":913},{"style":745},[914],{"type":419,"value":915},"}\n",{"type":414,"tag":415,"props":917,"children":918},{},[919],{"type":419,"value":920},"First, let's list the secrets in the Key Vault:",{"type":414,"tag":415,"props":922,"children":923},{},[924],{"type":414,"tag":609,"props":925,"children":929},{"alt":926,"className":927,"src":928},"An Azure CLI command that lists Key Vault secrets in terminal.",[613,614],"/posts/images/httpclientssecrets_script_1.png",[],{"type":414,"tag":415,"props":931,"children":932},{},[933],{"type":419,"value":934},"The output of the command is not that easy to read because it's JSON and there are some properties we are not interested in. However, Azure CLI supports different output formats and can be used with JMESPath expressions to query the output of a command like this:",{"type":414,"tag":415,"props":936,"children":937},{},[938],{"type":414,"tag":609,"props":939,"children":943},{"alt":940,"className":941,"src":942},"An Azure CLI command using JMESPath that lists Key Vault secrets in terminal.",[613,614],"/posts/images/httpclientssecrets_script_2.png",[],{"type":414,"tag":415,"props":945,"children":946},{},[947,949,955],{"type":419,"value":948},"It's nice but I won't need to use this because I can use Nushell (aka Nu) pipelines where everything is structured data that can be filtered, selected, and sorted. To bring the Azure CLI command output into a Nu pipeline, I can use the ",{"type":414,"tag":479,"props":950,"children":952},{"className":951},[],[953],{"type":419,"value":954},"from json",{"type":419,"value":956}," command.",{"type":414,"tag":415,"props":958,"children":959},{},[960],{"type":414,"tag":609,"props":961,"children":965},{"alt":962,"className":963,"src":964},"The output of the \"az keyvault secret list --vault-name httpclient-vault | from json\" command in terminal.",[613,614],"/posts/images/httpclientssecrets_script_3.png",[],{"type":414,"tag":623,"props":967,"children":968},{"icon":658},[969],{"type":414,"tag":415,"props":970,"children":971},{},[972,974,980],{"type":419,"value":973},"Nu has many ",{"type":414,"tag":479,"props":975,"children":977},{"className":976},[],[978],{"type":419,"value":979},"from",{"type":419,"value":981}," commands to convert data from different formats to structured data/table.",{"type":414,"tag":415,"props":983,"children":984},{},[985,987,993],{"type":419,"value":986},"You probably have noticed that the Azure CLI command we used to list the secrets does not provide their values. To retrieve the secret values we have to call another command for each secret using the id of the secret like this: ",{"type":414,"tag":479,"props":988,"children":990},{"className":989},[],[991],{"type":419,"value":992},"az keyvault secret show --id $secretId",{"type":419,"value":457},{"type":414,"tag":415,"props":995,"children":996},{},[997],{"type":414,"tag":609,"props":998,"children":1002},{"alt":999,"className":1000,"src":1001},"An Azure CLI command that get a secret from Key Vault in terminal.",[613,614],"/posts/images/httpclientssecrets_script_4.png",[],{"type":414,"tag":415,"props":1004,"children":1005},{},[1006,1008,1013,1015,1021],{"type":419,"value":1007},"Again we can use the ",{"type":414,"tag":479,"props":1009,"children":1011},{"className":1010},[],[1012],{"type":419,"value":954},{"type":419,"value":1014}," command, and the ",{"type":414,"tag":479,"props":1016,"children":1018},{"className":1017},[],[1019],{"type":419,"value":1020},"get",{"type":419,"value":1022}," command to only retrieve the value of a secret.",{"type":414,"tag":415,"props":1024,"children":1025},{},[1026],{"type":414,"tag":609,"props":1027,"children":1031},{"alt":1028,"className":1029,"src":1030},"The output of the nushell script retrieving a secret value from keyvault.",[613,614],"/posts/images/httpclientssecrets_script_5.png",[],{"type":414,"tag":415,"props":1033,"children":1034},{},[1035,1037,1043],{"type":419,"value":1036},"Now that we know how to retrieve the value of a secret, we can insert a new column ",{"type":414,"tag":479,"props":1038,"children":1040},{"className":1039},[],[1041],{"type":419,"value":1042},"value",{"type":419,"value":1044}," into our table that will be filled with the value of each secret retrieved   using the previous command:",{"type":414,"tag":415,"props":1046,"children":1047},{},[1048],{"type":414,"tag":609,"props":1049,"children":1053},{"alt":1050,"className":1051,"src":1052},"The output of the nushell script retrieving a list of secrets from keyvault.",[613,614],"/posts/images/httpclientssecrets_script_6.png",[],{"type":414,"tag":415,"props":1055,"children":1056},{},[1057,1059,1065,1067,1073,1075,1081],{"type":419,"value":1058},"The ",{"type":414,"tag":479,"props":1060,"children":1062},{"className":1061},[],[1063],{"type":419,"value":1064},"{|secret| (az keyvault secret show --id $secret.id | from json | get value)}",{"type":419,"value":1066}," part is a block that is executed for each row. The ",{"type":414,"tag":479,"props":1068,"children":1070},{"className":1069},[],[1071],{"type":419,"value":1072},"secret",{"type":419,"value":1074}," is the parameter of the block which represents the row, with the values of the columns for this row being available as properties of the variable ",{"type":414,"tag":479,"props":1076,"children":1078},{"className":1077},[],[1079],{"type":419,"value":1080},"$secret",{"type":419,"value":1082},". As the command was becoming long for a single line, we wrapped it in parentheses that allow us to write the command on multiple lines.",{"type":414,"tag":415,"props":1084,"children":1085},{},[1086],{"type":419,"value":1087},"As we are only interested in the columns \"name\" and \"value\", we only select them.",{"type":414,"tag":415,"props":1089,"children":1090},{},[1091],{"type":414,"tag":609,"props":1092,"children":1096},{"alt":1093,"className":1094,"src":1095},"The output of the nushell script retrieving Azure Key Vault secrets (name and value).",[613,614],"/posts/images/httpclientssecrets_script_7.png",[],{"type":414,"tag":415,"props":1098,"children":1099},{},[1100,1102,1108],{"type":419,"value":1101},"We have to reorganize the data to make key-value pairs where keys come from the column name and values from the column value. We can use the ",{"type":414,"tag":479,"props":1103,"children":1105},{"className":1104},[],[1106],{"type":419,"value":1107},"transpose",{"type":419,"value":1109}," with the proper flags to do that:",{"type":414,"tag":415,"props":1111,"children":1112},{},[1113],{"type":414,"tag":609,"props":1114,"children":1117},{"alt":1093,"className":1115,"src":1116},[613,614],"/posts/images/httpclientssecrets_script_8.png",[],{"type":414,"tag":415,"props":1119,"children":1120},{},[1121],{"type":419,"value":1122},"Then we wrap the key-value pairs in a JSON object corresponding to the development environment:",{"type":414,"tag":415,"props":1124,"children":1125},{},[1126],{"type":414,"tag":609,"props":1127,"children":1131},{"alt":1128,"className":1129,"src":1130},"The output of the nushell script creating a JSON object from Azure Key Vault secrets.",[613,614],"/posts/images/httpclientssecrets_script_9.png",[],{"type":414,"tag":415,"props":1133,"children":1134},{},[1135,1137,1143],{"type":419,"value":1136},"We can check we get the JSON we want with the ",{"type":414,"tag":479,"props":1138,"children":1140},{"className":1139},[],[1141],{"type":419,"value":1142},"to json",{"type":419,"value":956},{"type":414,"tag":415,"props":1145,"children":1146},{},[1147],{"type":414,"tag":609,"props":1148,"children":1152},{"alt":1149,"className":1150,"src":1151},"The output of the nushell script creating a JSON string from Azure Key Vault secrets.",[613,614],"/posts/images/httpclientssecrets_script_10.png",[],{"type":414,"tag":415,"props":1154,"children":1155},{},[1156,1158,1163],{"type":419,"value":1157},"And finally, we can save the data in a ",{"type":414,"tag":479,"props":1159,"children":1161},{"className":1160},[],[1162],{"type":419,"value":602},{"type":419,"value":1164}," file using the save command.",{"type":414,"tag":415,"props":1166,"children":1167},{},[1168],{"type":419,"value":1169},"Here is the final script 🔽:",{"type":414,"tag":503,"props":1171,"children":1174},{"className":1172,"code":1173,"language":243,"meta":401,"style":401},"language-nushell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","(\n  az keyvault secret list --vault-name httpclient-vault |\n  from json |\n  insert value {|secret| (az keyvault secret show --id $secret.id | from json | get value)} |\n  select name value |\n  transpose -rd |\n  { development: $in } |\n  save http-client.private.env.json\n)\n",[1175],{"type":414,"tag":479,"props":1176,"children":1177},{"__ignoreMap":401},[1178,1186,1230,1242,1343,1364,1386,1416,1429],{"type":414,"tag":512,"props":1179,"children":1180},{"class":514,"line":515},[1181],{"type":414,"tag":512,"props":1182,"children":1183},{"style":535},[1184],{"type":419,"value":1185},"(\n",{"type":414,"tag":512,"props":1187,"children":1188},{"class":514,"line":525},[1189,1194,1199,1204,1209,1214,1220,1225],{"type":414,"tag":512,"props":1190,"children":1191},{"style":793},[1192],{"type":419,"value":1193},"  az",{"type":414,"tag":512,"props":1195,"children":1196},{"style":812},[1197],{"type":419,"value":1198}," keyvault",{"type":414,"tag":512,"props":1200,"children":1201},{"style":812},[1202],{"type":419,"value":1203}," secret",{"type":414,"tag":512,"props":1205,"children":1206},{"style":812},[1207],{"type":419,"value":1208}," list",{"type":414,"tag":512,"props":1210,"children":1211},{"style":529},[1212],{"type":419,"value":1213}," --",{"type":414,"tag":512,"props":1215,"children":1217},{"style":1216},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[1218],{"type":419,"value":1219},"vault-name",{"type":414,"tag":512,"props":1221,"children":1222},{"style":812},[1223],{"type":419,"value":1224}," httpclient-vault",{"type":414,"tag":512,"props":1226,"children":1227},{"style":529},[1228],{"type":419,"value":1229}," |\n",{"type":414,"tag":512,"props":1231,"children":1232},{"class":514,"line":775},[1233,1238],{"type":414,"tag":512,"props":1234,"children":1235},{"style":541},[1236],{"type":419,"value":1237},"  from json",{"type":414,"tag":512,"props":1239,"children":1240},{"style":529},[1241],{"type":419,"value":1229},{"type":414,"tag":512,"props":1243,"children":1244},{"class":514,"line":784},[1245,1250,1255,1260,1265,1269,1274,1279,1283,1287,1292,1296,1301,1306,1310,1315,1320,1325,1329,1334,1339],{"type":414,"tag":512,"props":1246,"children":1247},{"style":541},[1248],{"type":419,"value":1249},"  insert",{"type":414,"tag":512,"props":1251,"children":1252},{"style":812},[1253],{"type":419,"value":1254}," value",{"type":414,"tag":512,"props":1256,"children":1257},{"style":745},[1258],{"type":419,"value":1259}," {",{"type":414,"tag":512,"props":1261,"children":1262},{"style":535},[1263],{"type":419,"value":1264},"|",{"type":414,"tag":512,"props":1266,"children":1267},{"style":1216},[1268],{"type":419,"value":1072},{"type":414,"tag":512,"props":1270,"children":1271},{"style":535},[1272],{"type":419,"value":1273},"| (",{"type":414,"tag":512,"props":1275,"children":1276},{"style":793},[1277],{"type":419,"value":1278},"az",{"type":414,"tag":512,"props":1280,"children":1281},{"style":812},[1282],{"type":419,"value":1198},{"type":414,"tag":512,"props":1284,"children":1285},{"style":812},[1286],{"type":419,"value":1203},{"type":414,"tag":512,"props":1288,"children":1289},{"style":812},[1290],{"type":419,"value":1291}," show",{"type":414,"tag":512,"props":1293,"children":1294},{"style":529},[1295],{"type":419,"value":1213},{"type":414,"tag":512,"props":1297,"children":1298},{"style":1216},[1299],{"type":419,"value":1300},"id",{"type":414,"tag":512,"props":1302,"children":1303},{"style":535},[1304],{"type":419,"value":1305}," $secret.id ",{"type":414,"tag":512,"props":1307,"children":1308},{"style":529},[1309],{"type":419,"value":1264},{"type":414,"tag":512,"props":1311,"children":1312},{"style":541},[1313],{"type":419,"value":1314}," from json",{"type":414,"tag":512,"props":1316,"children":1317},{"style":529},[1318],{"type":419,"value":1319}," |",{"type":414,"tag":512,"props":1321,"children":1322},{"style":541},[1323],{"type":419,"value":1324}," get",{"type":414,"tag":512,"props":1326,"children":1327},{"style":812},[1328],{"type":419,"value":1254},{"type":414,"tag":512,"props":1330,"children":1331},{"style":535},[1332],{"type":419,"value":1333},")",{"type":414,"tag":512,"props":1335,"children":1336},{"style":745},[1337],{"type":419,"value":1338},"}",{"type":414,"tag":512,"props":1340,"children":1341},{"style":529},[1342],{"type":419,"value":1229},{"type":414,"tag":512,"props":1344,"children":1345},{"class":514,"line":827},[1346,1351,1356,1360],{"type":414,"tag":512,"props":1347,"children":1348},{"style":541},[1349],{"type":419,"value":1350},"  select",{"type":414,"tag":512,"props":1352,"children":1353},{"style":812},[1354],{"type":419,"value":1355}," name",{"type":414,"tag":512,"props":1357,"children":1358},{"style":812},[1359],{"type":419,"value":1254},{"type":414,"tag":512,"props":1361,"children":1362},{"style":529},[1363],{"type":419,"value":1229},{"type":414,"tag":512,"props":1365,"children":1366},{"class":514,"line":865},[1367,1372,1377,1382],{"type":414,"tag":512,"props":1368,"children":1369},{"style":541},[1370],{"type":419,"value":1371},"  transpose",{"type":414,"tag":512,"props":1373,"children":1374},{"style":529},[1375],{"type":419,"value":1376}," -",{"type":414,"tag":512,"props":1378,"children":1379},{"style":1216},[1380],{"type":419,"value":1381},"rd",{"type":414,"tag":512,"props":1383,"children":1384},{"style":529},[1385],{"type":419,"value":1229},{"type":414,"tag":512,"props":1387,"children":1388},{"class":514,"line":900},[1389,1394,1399,1403,1408,1412],{"type":414,"tag":512,"props":1390,"children":1391},{"style":745},[1392],{"type":419,"value":1393},"  {",{"type":414,"tag":512,"props":1395,"children":1396},{"style":535},[1397],{"type":419,"value":1398}," development",{"type":414,"tag":512,"props":1400,"children":1401},{"style":529},[1402],{"type":419,"value":730},{"type":414,"tag":512,"props":1404,"children":1405},{"style":535},[1406],{"type":419,"value":1407}," $in ",{"type":414,"tag":512,"props":1409,"children":1410},{"style":745},[1411],{"type":419,"value":1338},{"type":414,"tag":512,"props":1413,"children":1414},{"style":529},[1415],{"type":419,"value":1229},{"type":414,"tag":512,"props":1417,"children":1418},{"class":514,"line":909},[1419,1424],{"type":414,"tag":512,"props":1420,"children":1421},{"style":541},[1422],{"type":419,"value":1423},"  save",{"type":414,"tag":512,"props":1425,"children":1426},{"style":812},[1427],{"type":419,"value":1428}," http-client.private.env.json\n",{"type":414,"tag":512,"props":1430,"children":1432},{"class":514,"line":1431},9,[1433],{"type":414,"tag":512,"props":1434,"children":1435},{"style":535},[1436],{"type":419,"value":1437},")\n",{"type":414,"tag":459,"props":1439,"children":1441},{"id":1440},"final-thoughts",[1442],{"type":419,"value":1443},"Final thoughts",{"type":414,"tag":415,"props":1445,"children":1446},{},[1447],{"type":419,"value":1448},"In this example, I scripted with Nu the retrieval of secrets from an Azure Key Vault, but it should not be too difficult to apply the same concepts to fetch secrets from another vault.",{"type":414,"tag":415,"props":1450,"children":1451},{},[1452,1454,1461],{"type":419,"value":1453},"I had fun playing with Azure CLI and Nushell to write this script but there are many other ways to do the same thing. There are also probably other tools or services (I have just came across ",{"type":414,"tag":422,"props":1455,"children":1458},{"href":1456,"rel":1457},"https://www.doppler.com/",[426],[1459],{"type":419,"value":1460},"Doppler",{"type":419,"value":1462}," which seems nice) that can help you manage secrets securely.",{"type":414,"tag":415,"props":1464,"children":1465},{},[1466],{"type":419,"value":1467},"I am not a Nushell expert but I find it awesome, and am considering making it my main shell. You should give it a try too. A big thank you to the people in the Nushell Discord that help me with my script ❤️.",{"type":414,"tag":1469,"props":1470,"children":1471},"style",{},[1472],{"type":419,"value":1473},"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":525,"depth":525,"links":1475},[1476,1477,1478,1479],{"id":461,"depth":525,"text":464},{"id":647,"depth":525,"text":650},{"id":672,"depth":525,"text":675},{"id":1440,"depth":525,"text":1443},"markdown","content:1.posts:39.http-clients-secrets.md","content","1.posts/39.http-clients-secrets.md","md",{"_path":97,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":96,"description":1486,"lead":1487,"date":1488,"badge":1489,"image":1490,"tags":1492,"body":1493,"_type":1480,"_id":4092,"_source":1482,"_file":4093,"_extension":1484},"By default when you use Pulumi, the state is managed by Pulumi Service which is very convenient as you can concentrate on building your project infrastructure instead of spending time on where to store the state and how to handle concurrency. However, sometimes for governance or pricing concerns, or any other reasons, you don't want to use Pulumi Service and you prefer to manage the state yourself with your own backend. In this article, we will see how we can do that using Azure.","Pulumi without Pulumi Service.","2021-12-14T00:00:00.000Z",{"label":266},{"src":1491},"/images/cloud-crave_1.jpg",[312,315,225,318,260,228],{"type":411,"children":1494,"toc":4074},[1495,1499,1505,1512,1517,1537,1545,1550,1555,1578,1587,1593,1598,1603,1626,1631,1637,1643,1655,1689,1694,1699,1705,1727,1736,1751,1756,1905,1910,2015,2020,2099,2104,2228,2233,2269,2275,2280,2305,2326,2416,2421,2441,2450,2456,2462,2467,2472,2478,2483,2488,2515,2520,2526,2531,2667,2680,2685,2761,2774,2846,2851,2902,2907,2943,2948,3043,3049,3054,3059,3073,3095,3104,3109,3115,3120,4051,4056,4070],{"type":414,"tag":415,"props":1496,"children":1497},{},[1498],{"type":419,"value":1486},{"type":414,"tag":459,"props":1500,"children":1502},{"id":1501},"a-quick-reminder-about-states-and-backends",[1503],{"type":419,"value":1504},"A quick reminder about states and backends",{"type":414,"tag":1506,"props":1507,"children":1509},"h3",{"id":1508},"what-is-this-state-we-need-to-store",[1510],{"type":419,"value":1511},"What is this state we need to store?",{"type":414,"tag":415,"props":1513,"children":1514},{},[1515],{"type":419,"value":1516},"Like other Infrastructure as Code platforms, Pulumi uses a declarative approach:",{"type":414,"tag":1518,"props":1519,"children":1520},"ul",{},[1521,1527,1532],{"type":414,"tag":1522,"props":1523,"children":1524},"li",{},[1525],{"type":419,"value":1526},"we write code to describe the desired state of our infrastructure",{"type":414,"tag":1522,"props":1528,"children":1529},{},[1530],{"type":419,"value":1531},"Pulumi engine compares this desired state with the current state of the infrastructure and determines what changes need to be made",{"type":414,"tag":1522,"props":1533,"children":1534},{},[1535],{"type":419,"value":1536},"Pulumi deploys these changes and updates the current state of the provisioned infrastructure",{"type":414,"tag":623,"props":1538,"children":1539},{"icon":625},[1540],{"type":414,"tag":415,"props":1541,"children":1542},{},[1543],{"type":419,"value":1544},"Some people think using Pulumi means adopting an imperative approach because we are using programming languages (so imperative languages) instead of using declarative languages (like YAML, JSON, and HCL). However, being declarative is not about the language used but about defining the \"what\" (the infrastructure we want to provision) instead of the \"how\" (the steps to provision this infrastructure). So Pulumi has the best of both worlds by being declarative while using programming languages.",{"type":414,"tag":415,"props":1546,"children":1547},{},[1548],{"type":419,"value":1549},"As you understood, being able to provision and modify an infrastructure with this declarative approach requires 2 states: the desired state and the current state of the infrastructure. The desired state is the infrastructure code that we usually store in a Git repository alongside the application code. The current state however is computed by the Pulumi engine each time we modify the infrastructure and needs to be stored somewhere.",{"type":414,"tag":415,"props":1551,"children":1552},{},[1553],{"type":419,"value":1554},"That is why we need a \"backend\" to use Pulumi, it's just a place to store the current state of the provisioned infrastructure.",{"type":414,"tag":415,"props":1556,"children":1557},{},[1558,1560,1567,1569,1576],{"type":419,"value":1559},"If you want more information about states and backend, Pulumi has a ",{"type":414,"tag":422,"props":1561,"children":1564},{"href":1562,"rel":1563},"https://www.pulumi.com/docs/intro/concepts/state/",[426],[1565],{"type":419,"value":1566},"documentation page",{"type":419,"value":1568}," about that and there is also ",{"type":414,"tag":422,"props":1570,"children":1573},{"href":1571,"rel":1572},"https://www.pulumi.com/docs/intro/concepts/how-pulumi-works/",[426],[1574],{"type":419,"value":1575},"a page",{"type":419,"value":1577}," about how Pulumi works.",{"type":414,"tag":415,"props":1579,"children":1580},{},[1581],{"type":414,"tag":609,"props":1582,"children":1586},{"alt":1583,"className":1584,"src":1585},"Diagram of how Pulumi works.",[613,614],"/posts/images/pulumiazurebackend_schema_1.png",[],{"type":414,"tag":1506,"props":1588,"children":1590},{"id":1589},"what-backends-can-we-use-to-manage-the-infrastructure",[1591],{"type":419,"value":1592},"What \"backends\" can we use to manage the infrastructure?",{"type":414,"tag":415,"props":1594,"children":1595},{},[1596],{"type":419,"value":1597},"The default backend is Pulumi Service which is a web application that stores the infrastructure state and has additional features like concurrent state locking, team policies, or deployment history. This service is managed by Pulumi, is free for individuals but charged for teams, and enterprises. It can be self-hosted in the enterprise plan. Just as a side note, Pulumi Service (along with support and training) is how the company Pulumi makes money because everything else is free and open source.",{"type":414,"tag":415,"props":1599,"children":1600},{},[1601],{"type":419,"value":1602},"Yet, we don't have to pay anything to use Pulumi because Pulumi Service, no matter how good it may be, is not the only solution to store the infrastructure state. Indeed, Pulumi supports other backends that we can manage ourselves:",{"type":414,"tag":1518,"props":1604,"children":1605},{},[1606,1611,1616,1621],{"type":414,"tag":1522,"props":1607,"children":1608},{},[1609],{"type":419,"value":1610},"Local Filesystem",{"type":414,"tag":1522,"props":1612,"children":1613},{},[1614],{"type":419,"value":1615},"AWS S3 (or compatible server)",{"type":414,"tag":1522,"props":1617,"children":1618},{},[1619],{"type":419,"value":1620},"Google Cloud Storage",{"type":414,"tag":1522,"props":1622,"children":1623},{},[1624],{"type":419,"value":1625},"Azure Blob Storage",{"type":414,"tag":415,"props":1627,"children":1628},{},[1629],{"type":419,"value":1630},"In the rest of this article, we will see how to use Pulumi with Azure Blob Storage as the backend for our infrastructure state.",{"type":414,"tag":459,"props":1632,"children":1634},{"id":1633},"using-pulumi-with-the-azure-blob-storage-backend",[1635],{"type":419,"value":1636},"Using Pulumi with the Azure Blob Storage backend",{"type":414,"tag":1506,"props":1638,"children":1640},{"id":1639},"what-do-we-need",[1641],{"type":419,"value":1642},"What do we need?",{"type":414,"tag":415,"props":1644,"children":1645},{},[1646,1653],{"type":414,"tag":422,"props":1647,"children":1650},{"href":1648,"rel":1649},"https://www.pulumi.com/docs/intro/concepts/state/#logging-into-the-azure-blob-storage-backend",[426],[1651],{"type":419,"value":1652},"Pulumi documentation",{"type":419,"value":1654}," on using Azure Blob Storage backend is short. It only says that we need to:",{"type":414,"tag":1518,"props":1656,"children":1657},{},[1658,1663,1668],{"type":414,"tag":1522,"props":1659,"children":1660},{},[1661],{"type":419,"value":1662},"set the AZURE_STORAGE_ACCOUNT environment variable to specify the Azure storage account to use",{"type":414,"tag":1522,"props":1664,"children":1665},{},[1666],{"type":419,"value":1667},"set the AZURE_STORAGE_KEY or the AZURE_STORAGE_SAS_TOKEN environment variables to let Pulumi access the storage",{"type":414,"tag":1522,"props":1669,"children":1670},{},[1671,1673,1679,1681,1687],{"type":419,"value":1672},"execute the following command ",{"type":414,"tag":479,"props":1674,"children":1676},{"className":1675},[],[1677],{"type":419,"value":1678},"pulumi login azblob://\u003Ccontainer-path>",{"type":419,"value":1680}," where ",{"type":414,"tag":479,"props":1682,"children":1684},{"className":1683},[],[1685],{"type":419,"value":1686},"container-path",{"type":419,"value":1688}," is the path to a blob container in the storage account",{"type":414,"tag":415,"props":1690,"children":1691},{},[1692],{"type":419,"value":1693},"Once this command is executed, we can start using Pulumi as we would with any other backend. The infrastructure's current state will automatically be stored in the blob container you specified. It will be compared to the desired state when a change is made in the code to know what resources need to be created/updated/deleted.",{"type":414,"tag":415,"props":1695,"children":1696},{},[1697],{"type":419,"value":1698},"In fact, that is not very complex. Nevertheless, the documentation assumes we already have created an Azure storage account with a blob container in it and retrieved the key to access it. That is not the case, so now that we know what we need let's script it!",{"type":414,"tag":1506,"props":1700,"children":1702},{"id":1701},"how-to-create-and-configure-the-azure-blob-storage-backend",[1703],{"type":419,"value":1704},"How to create and configure the Azure Blob Storage backend?",{"type":414,"tag":415,"props":1706,"children":1707},{},[1708,1710,1717,1719,1725],{"type":419,"value":1709},"For me, the easiest way to write a script to create and configure the storage account we need is to use Azure CLI. One nice way of writing Azure CLI scripts is to do it in vscode with the ",{"type":414,"tag":422,"props":1711,"children":1714},{"href":1712,"rel":1713},"https://marketplace.visualstudio.com/items?itemName=ms-vscode.azurecli",[426],[1715],{"type":419,"value":1716},"Azure CLI Tools extension",{"type":419,"value":1718},": you can create ",{"type":414,"tag":479,"props":1720,"children":1722},{"className":1721},[],[1723],{"type":419,"value":1724},".azcli",{"type":419,"value":1726}," files with IntelliSense on them and run the commands you are writing in the integrated terminal (see screenshot below).",{"type":414,"tag":415,"props":1728,"children":1729},{},[1730],{"type":414,"tag":609,"props":1731,"children":1735},{"alt":1732,"className":1733,"src":1734},"Azure CLI script in vscode.",[613,614],"/posts/images/pulumiazurebackend_vscode_1.png",[],{"type":414,"tag":623,"props":1737,"children":1738},{"icon":625},[1739],{"type":414,"tag":415,"props":1740,"children":1741},{},[1742,1744,1749],{"type":419,"value":1743},"If you are not familiar with Azure CLI, you can check my article \"",{"type":414,"tag":422,"props":1745,"children":1747},{"href":683,"rel":1746},[426],[1748],{"type":419,"value":15},{"type":419,"value":1750},"\".",{"type":414,"tag":415,"props":1752,"children":1753},{},[1754],{"type":419,"value":1755},"Let's first define a few environment variables: the name of the resource group that will contain our storage account, its location, and the name of the storage account (I am using PowerShell but don't forget to change the syntax if you are using another shell like bash).",{"type":414,"tag":503,"props":1757,"children":1760},{"className":1758,"code":1759,"language":248,"meta":401,"style":401},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","$random=Get-Random -Maximum 1000\n$location=\"West Europe\"\n$rgName=\"rg-iacstate-westeu-$random\"\n$saName=\"stiacstate$random\"\n",[1761],{"type":414,"tag":479,"props":1762,"children":1763},{"__ignoreMap":401},[1764,1802,1831,1868],{"type":414,"tag":512,"props":1765,"children":1766},{"class":514,"line":515},[1767,1772,1777,1782,1788,1792,1797],{"type":414,"tag":512,"props":1768,"children":1769},{"style":745},[1770],{"type":419,"value":1771},"$",{"type":414,"tag":512,"props":1773,"children":1774},{"style":535},[1775],{"type":419,"value":1776},"random",{"type":414,"tag":512,"props":1778,"children":1779},{"style":745},[1780],{"type":419,"value":1781},"=",{"type":414,"tag":512,"props":1783,"children":1785},{"style":1784},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[1786],{"type":419,"value":1787},"Get-Random",{"type":414,"tag":512,"props":1789,"children":1790},{"style":745},[1791],{"type":419,"value":1376},{"type":414,"tag":512,"props":1793,"children":1794},{"style":535},[1795],{"type":419,"value":1796},"Maximum ",{"type":414,"tag":512,"props":1798,"children":1799},{"style":541},[1800],{"type":419,"value":1801},"1000\n",{"type":414,"tag":512,"props":1803,"children":1804},{"class":514,"line":525},[1805,1809,1814,1818,1822,1827],{"type":414,"tag":512,"props":1806,"children":1807},{"style":745},[1808],{"type":419,"value":1771},{"type":414,"tag":512,"props":1810,"children":1811},{"style":535},[1812],{"type":419,"value":1813},"location",{"type":414,"tag":512,"props":1815,"children":1816},{"style":745},[1817],{"type":419,"value":1781},{"type":414,"tag":512,"props":1819,"children":1820},{"style":745},[1821],{"type":419,"value":767},{"type":414,"tag":512,"props":1823,"children":1824},{"style":812},[1825],{"type":419,"value":1826},"West Europe",{"type":414,"tag":512,"props":1828,"children":1829},{"style":745},[1830],{"type":419,"value":897},{"type":414,"tag":512,"props":1832,"children":1833},{"class":514,"line":775},[1834,1838,1843,1847,1851,1856,1860,1864],{"type":414,"tag":512,"props":1835,"children":1836},{"style":745},[1837],{"type":419,"value":1771},{"type":414,"tag":512,"props":1839,"children":1840},{"style":535},[1841],{"type":419,"value":1842},"rgName",{"type":414,"tag":512,"props":1844,"children":1845},{"style":745},[1846],{"type":419,"value":1781},{"type":414,"tag":512,"props":1848,"children":1849},{"style":745},[1850],{"type":419,"value":767},{"type":414,"tag":512,"props":1852,"children":1853},{"style":812},[1854],{"type":419,"value":1855},"rg-iacstate-westeu-",{"type":414,"tag":512,"props":1857,"children":1858},{"style":745},[1859],{"type":419,"value":1771},{"type":414,"tag":512,"props":1861,"children":1862},{"style":535},[1863],{"type":419,"value":1776},{"type":414,"tag":512,"props":1865,"children":1866},{"style":745},[1867],{"type":419,"value":897},{"type":414,"tag":512,"props":1869,"children":1870},{"class":514,"line":784},[1871,1875,1880,1884,1888,1893,1897,1901],{"type":414,"tag":512,"props":1872,"children":1873},{"style":745},[1874],{"type":419,"value":1771},{"type":414,"tag":512,"props":1876,"children":1877},{"style":535},[1878],{"type":419,"value":1879},"saName",{"type":414,"tag":512,"props":1881,"children":1882},{"style":745},[1883],{"type":419,"value":1781},{"type":414,"tag":512,"props":1885,"children":1886},{"style":745},[1887],{"type":419,"value":767},{"type":414,"tag":512,"props":1889,"children":1890},{"style":812},[1891],{"type":419,"value":1892},"stiacstate",{"type":414,"tag":512,"props":1894,"children":1895},{"style":745},[1896],{"type":419,"value":1771},{"type":414,"tag":512,"props":1898,"children":1899},{"style":535},[1900],{"type":419,"value":1776},{"type":414,"tag":512,"props":1902,"children":1903},{"style":745},[1904],{"type":419,"value":897},{"type":414,"tag":415,"props":1906,"children":1907},{},[1908],{"type":419,"value":1909},"Then let's create our resource group and our storage account:",{"type":414,"tag":503,"props":1911,"children":1915},{"className":1912,"code":1913,"language":1914,"meta":401,"style":401},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","az group create -n $rgName -l $location\naz storage account create -g $rgName -n $saName -l $location --sku Standard_LRS\n","bash",[1916],{"type":414,"tag":479,"props":1917,"children":1918},{"__ignoreMap":401},[1919,1956],{"type":414,"tag":512,"props":1920,"children":1921},{"class":514,"line":515},[1922,1926,1931,1936,1941,1946,1951],{"type":414,"tag":512,"props":1923,"children":1924},{"style":793},[1925],{"type":419,"value":1278},{"type":414,"tag":512,"props":1927,"children":1928},{"style":812},[1929],{"type":419,"value":1930}," group",{"type":414,"tag":512,"props":1932,"children":1933},{"style":812},[1934],{"type":419,"value":1935}," create",{"type":414,"tag":512,"props":1937,"children":1938},{"style":812},[1939],{"type":419,"value":1940}," -n",{"type":414,"tag":512,"props":1942,"children":1943},{"style":535},[1944],{"type":419,"value":1945}," $rgName ",{"type":414,"tag":512,"props":1947,"children":1948},{"style":812},[1949],{"type":419,"value":1950},"-l",{"type":414,"tag":512,"props":1952,"children":1953},{"style":535},[1954],{"type":419,"value":1955}," $location\n",{"type":414,"tag":512,"props":1957,"children":1958},{"class":514,"line":525},[1959,1963,1968,1973,1977,1982,1986,1991,1996,2000,2005,2010],{"type":414,"tag":512,"props":1960,"children":1961},{"style":793},[1962],{"type":419,"value":1278},{"type":414,"tag":512,"props":1964,"children":1965},{"style":812},[1966],{"type":419,"value":1967}," storage",{"type":414,"tag":512,"props":1969,"children":1970},{"style":812},[1971],{"type":419,"value":1972}," account",{"type":414,"tag":512,"props":1974,"children":1975},{"style":812},[1976],{"type":419,"value":1935},{"type":414,"tag":512,"props":1978,"children":1979},{"style":812},[1980],{"type":419,"value":1981}," -g",{"type":414,"tag":512,"props":1983,"children":1984},{"style":535},[1985],{"type":419,"value":1945},{"type":414,"tag":512,"props":1987,"children":1988},{"style":812},[1989],{"type":419,"value":1990},"-n",{"type":414,"tag":512,"props":1992,"children":1993},{"style":535},[1994],{"type":419,"value":1995}," $saName ",{"type":414,"tag":512,"props":1997,"children":1998},{"style":812},[1999],{"type":419,"value":1950},{"type":414,"tag":512,"props":2001,"children":2002},{"style":535},[2003],{"type":419,"value":2004}," $location ",{"type":414,"tag":512,"props":2006,"children":2007},{"style":812},[2008],{"type":419,"value":2009},"--sku",{"type":414,"tag":512,"props":2011,"children":2012},{"style":812},[2013],{"type":419,"value":2014}," Standard_LRS\n",{"type":414,"tag":415,"props":2016,"children":2017},{},[2018],{"type":419,"value":2019},"The key to access the storage account can be retrieved with the following command:",{"type":414,"tag":503,"props":2021,"children":2023},{"className":1912,"code":2022,"language":1914,"meta":401,"style":401},"az storage account keys list --account-name $saName -g $rgName -o tsv --query '[0].value'\n",[2024],{"type":414,"tag":479,"props":2025,"children":2026},{"__ignoreMap":401},[2027],{"type":414,"tag":512,"props":2028,"children":2029},{"class":514,"line":515},[2030,2034,2038,2042,2047,2051,2056,2060,2065,2069,2074,2079,2084,2089,2094],{"type":414,"tag":512,"props":2031,"children":2032},{"style":793},[2033],{"type":419,"value":1278},{"type":414,"tag":512,"props":2035,"children":2036},{"style":812},[2037],{"type":419,"value":1967},{"type":414,"tag":512,"props":2039,"children":2040},{"style":812},[2041],{"type":419,"value":1972},{"type":414,"tag":512,"props":2043,"children":2044},{"style":812},[2045],{"type":419,"value":2046}," keys",{"type":414,"tag":512,"props":2048,"children":2049},{"style":812},[2050],{"type":419,"value":1208},{"type":414,"tag":512,"props":2052,"children":2053},{"style":812},[2054],{"type":419,"value":2055}," --account-name",{"type":414,"tag":512,"props":2057,"children":2058},{"style":535},[2059],{"type":419,"value":1995},{"type":414,"tag":512,"props":2061,"children":2062},{"style":812},[2063],{"type":419,"value":2064},"-g",{"type":414,"tag":512,"props":2066,"children":2067},{"style":535},[2068],{"type":419,"value":1945},{"type":414,"tag":512,"props":2070,"children":2071},{"style":812},[2072],{"type":419,"value":2073},"-o",{"type":414,"tag":512,"props":2075,"children":2076},{"style":812},[2077],{"type":419,"value":2078}," tsv",{"type":414,"tag":512,"props":2080,"children":2081},{"style":812},[2082],{"type":419,"value":2083}," --query",{"type":414,"tag":512,"props":2085,"children":2086},{"style":745},[2087],{"type":419,"value":2088}," '",{"type":414,"tag":512,"props":2090,"children":2091},{"style":812},[2092],{"type":419,"value":2093},"[0].value",{"type":414,"tag":512,"props":2095,"children":2096},{"style":745},[2097],{"type":419,"value":2098},"'\n",{"type":414,"tag":415,"props":2100,"children":2101},{},[2102],{"type":419,"value":2103},"Using this command, we can now set the environment variables that will be used by the Pulumi CLI to access our Azure Blob Storage account backend:",{"type":414,"tag":503,"props":2105,"children":2107},{"className":1758,"code":2106,"language":248,"meta":401,"style":401},"$env:AZURE_STORAGE_KEY=$(az storage account keys list -n $saName -g $rgName -o tsv --query '[0].value')\n$env:AZURE_STORAGE_ACCOUNT=$saName\n",[2108],{"type":414,"tag":479,"props":2109,"children":2110},{"__ignoreMap":401},[2111,2206],{"type":414,"tag":512,"props":2112,"children":2113},{"class":514,"line":515},[2114,2118,2123,2128,2133,2138,2143,2147,2152,2156,2161,2165,2170,2174,2179,2184,2189,2194,2198,2202],{"type":414,"tag":512,"props":2115,"children":2116},{"style":745},[2117],{"type":419,"value":1771},{"type":414,"tag":512,"props":2119,"children":2120},{"style":535},[2121],{"type":419,"value":2122},"env:AZURE_STORAGE_KEY",{"type":414,"tag":512,"props":2124,"children":2125},{"style":745},[2126],{"type":419,"value":2127},"=$(",{"type":414,"tag":512,"props":2129,"children":2130},{"style":535},[2131],{"type":419,"value":2132},"az storage account keys list ",{"type":414,"tag":512,"props":2134,"children":2135},{"style":745},[2136],{"type":419,"value":2137},"-",{"type":414,"tag":512,"props":2139,"children":2140},{"style":535},[2141],{"type":419,"value":2142},"n ",{"type":414,"tag":512,"props":2144,"children":2145},{"style":745},[2146],{"type":419,"value":1771},{"type":414,"tag":512,"props":2148,"children":2149},{"style":535},[2150],{"type":419,"value":2151},"saName ",{"type":414,"tag":512,"props":2153,"children":2154},{"style":745},[2155],{"type":419,"value":2137},{"type":414,"tag":512,"props":2157,"children":2158},{"style":535},[2159],{"type":419,"value":2160},"g ",{"type":414,"tag":512,"props":2162,"children":2163},{"style":745},[2164],{"type":419,"value":1771},{"type":414,"tag":512,"props":2166,"children":2167},{"style":535},[2168],{"type":419,"value":2169},"rgName ",{"type":414,"tag":512,"props":2171,"children":2172},{"style":745},[2173],{"type":419,"value":2137},{"type":414,"tag":512,"props":2175,"children":2176},{"style":535},[2177],{"type":419,"value":2178},"o tsv ",{"type":414,"tag":512,"props":2180,"children":2181},{"style":745},[2182],{"type":419,"value":2183},"--",{"type":414,"tag":512,"props":2185,"children":2186},{"style":535},[2187],{"type":419,"value":2188},"query ",{"type":414,"tag":512,"props":2190,"children":2191},{"style":745},[2192],{"type":419,"value":2193},"'",{"type":414,"tag":512,"props":2195,"children":2196},{"style":812},[2197],{"type":419,"value":2093},{"type":414,"tag":512,"props":2199,"children":2200},{"style":745},[2201],{"type":419,"value":2193},{"type":414,"tag":512,"props":2203,"children":2204},{"style":745},[2205],{"type":419,"value":1437},{"type":414,"tag":512,"props":2207,"children":2208},{"class":514,"line":525},[2209,2213,2218,2223],{"type":414,"tag":512,"props":2210,"children":2211},{"style":745},[2212],{"type":419,"value":1771},{"type":414,"tag":512,"props":2214,"children":2215},{"style":535},[2216],{"type":419,"value":2217},"env:AZURE_STORAGE_ACCOUNT",{"type":414,"tag":512,"props":2219,"children":2220},{"style":745},[2221],{"type":419,"value":2222},"=$",{"type":414,"tag":512,"props":2224,"children":2225},{"style":535},[2226],{"type":419,"value":2227},"saName\n",{"type":414,"tag":415,"props":2229,"children":2230},{},[2231],{"type":419,"value":2232},"And finally, we can create the blob container that will contain the infrastructure state:",{"type":414,"tag":503,"props":2234,"children":2236},{"className":1912,"code":2235,"language":1914,"meta":401,"style":401},"az storage container create -n iacstate\n",[2237],{"type":414,"tag":479,"props":2238,"children":2239},{"__ignoreMap":401},[2240],{"type":414,"tag":512,"props":2241,"children":2242},{"class":514,"line":515},[2243,2247,2251,2256,2260,2264],{"type":414,"tag":512,"props":2244,"children":2245},{"style":793},[2246],{"type":419,"value":1278},{"type":414,"tag":512,"props":2248,"children":2249},{"style":812},[2250],{"type":419,"value":1967},{"type":414,"tag":512,"props":2252,"children":2253},{"style":812},[2254],{"type":419,"value":2255}," container",{"type":414,"tag":512,"props":2257,"children":2258},{"style":812},[2259],{"type":419,"value":1935},{"type":414,"tag":512,"props":2261,"children":2262},{"style":812},[2263],{"type":419,"value":1940},{"type":414,"tag":512,"props":2265,"children":2266},{"style":812},[2267],{"type":419,"value":2268}," iacstate\n",{"type":414,"tag":1506,"props":2270,"children":2272},{"id":2271},"how-to-provision-your-project-infrastructure-using-the-azure-blob-storage-backend",[2273],{"type":419,"value":2274},"How to provision your project infrastructure using the Azure Blob Storage backend?",{"type":414,"tag":415,"props":2276,"children":2277},{},[2278],{"type":419,"value":2279},"Now that our blob container exists, we can use the pulumi login command we already talked about to indicate pulumi to use the newly created azure blob storage as the backend.",{"type":414,"tag":503,"props":2281,"children":2283},{"className":1758,"code":2282,"language":248,"meta":401,"style":401},"pulumi login azblob://iacstate\n",[2284],{"type":414,"tag":479,"props":2285,"children":2286},{"__ignoreMap":401},[2287],{"type":414,"tag":512,"props":2288,"children":2289},{"class":514,"line":515},[2290,2295,2300],{"type":414,"tag":512,"props":2291,"children":2292},{"style":535},[2293],{"type":419,"value":2294},"pulumi login azblob:",{"type":414,"tag":512,"props":2296,"children":2297},{"style":745},[2298],{"type":419,"value":2299},"//",{"type":414,"tag":512,"props":2301,"children":2302},{"style":535},[2303],{"type":419,"value":2304},"iacstate\n",{"type":414,"tag":415,"props":2306,"children":2307},{},[2308,2310,2316,2318,2324],{"type":419,"value":2309},"To verify Pulumi can correctly provision cloud resources using our Azure Blob Storage backend, we can create a new Pulumi project using the ",{"type":414,"tag":479,"props":2311,"children":2313},{"className":2312},[],[2314],{"type":419,"value":2315},"azure-csharp",{"type":419,"value":2317}," template and deploy the infrastructure with the ",{"type":414,"tag":479,"props":2319,"children":2321},{"className":2320},[],[2322],{"type":419,"value":2323},"pulumi up",{"type":419,"value":2325}," command:",{"type":414,"tag":503,"props":2327,"children":2329},{"className":1758,"code":2328,"language":248,"meta":401,"style":401},"mkdir infra;cd infra;\npulumi new azure-csharp -n AzureStorageBackend -s dev -y\npulumi up -y\n",[2330],{"type":414,"tag":479,"props":2331,"children":2332},{"__ignoreMap":401},[2333,2356,2400],{"type":414,"tag":512,"props":2334,"children":2335},{"class":514,"line":515},[2336,2341,2346,2351],{"type":414,"tag":512,"props":2337,"children":2338},{"style":535},[2339],{"type":419,"value":2340},"mkdir infra",{"type":414,"tag":512,"props":2342,"children":2343},{"style":745},[2344],{"type":419,"value":2345},";",{"type":414,"tag":512,"props":2347,"children":2348},{"style":535},[2349],{"type":419,"value":2350},"cd infra",{"type":414,"tag":512,"props":2352,"children":2353},{"style":745},[2354],{"type":419,"value":2355},";\n",{"type":414,"tag":512,"props":2357,"children":2358},{"class":514,"line":525},[2359,2364,2368,2373,2377,2382,2386,2391,2395],{"type":414,"tag":512,"props":2360,"children":2361},{"style":535},[2362],{"type":419,"value":2363},"pulumi new azure",{"type":414,"tag":512,"props":2365,"children":2366},{"style":745},[2367],{"type":419,"value":2137},{"type":414,"tag":512,"props":2369,"children":2370},{"style":535},[2371],{"type":419,"value":2372},"csharp ",{"type":414,"tag":512,"props":2374,"children":2375},{"style":745},[2376],{"type":419,"value":2137},{"type":414,"tag":512,"props":2378,"children":2379},{"style":535},[2380],{"type":419,"value":2381},"n AzureStorageBackend ",{"type":414,"tag":512,"props":2383,"children":2384},{"style":745},[2385],{"type":419,"value":2137},{"type":414,"tag":512,"props":2387,"children":2388},{"style":535},[2389],{"type":419,"value":2390},"s dev ",{"type":414,"tag":512,"props":2392,"children":2393},{"style":745},[2394],{"type":419,"value":2137},{"type":414,"tag":512,"props":2396,"children":2397},{"style":535},[2398],{"type":419,"value":2399},"y\n",{"type":414,"tag":512,"props":2401,"children":2402},{"class":514,"line":775},[2403,2408,2412],{"type":414,"tag":512,"props":2404,"children":2405},{"style":535},[2406],{"type":419,"value":2407},"pulumi up ",{"type":414,"tag":512,"props":2409,"children":2410},{"style":745},[2411],{"type":419,"value":2137},{"type":414,"tag":512,"props":2413,"children":2414},{"style":535},[2415],{"type":419,"value":2399},{"type":414,"tag":415,"props":2417,"children":2418},{},[2419],{"type":419,"value":2420},"When executing these commands, Pulumi will ask us to provide a passphrase. Why is that? It is to encrypt secrets contained in the infrastructure state. This way no secret is stored in plain text in the state.",{"type":414,"tag":415,"props":2422,"children":2423},{},[2424,2426,2431,2433,2439],{"type":419,"value":2425},"Once the ",{"type":414,"tag":479,"props":2427,"children":2429},{"className":2428},[],[2430],{"type":419,"value":2323},{"type":419,"value":2432}," command is finished, the infrastructure requested is provisioned, and we can see a new state file has been created in the ",{"type":414,"tag":479,"props":2434,"children":2436},{"className":2435},[],[2437],{"type":419,"value":2438},"iacstate",{"type":419,"value":2440}," blob container.",{"type":414,"tag":415,"props":2442,"children":2443},{},[2444],{"type":414,"tag":609,"props":2445,"children":2449},{"alt":2446,"className":2447,"src":2448},"Azure Blob container explorer showing the Pulumi state file.",[613,614],"/posts/images/pulumiazurebackend_azure_1.png",[],{"type":414,"tag":459,"props":2451,"children":2453},{"id":2452},"managing-state-sensitive-data",[2454],{"type":419,"value":2455},"Managing state sensitive data",{"type":414,"tag":1506,"props":2457,"children":2459},{"id":2458},"why-is-it-needed-to-protect-sensitive-data-in-the-state",[2460],{"type":419,"value":2461},"Why is it needed to protect sensitive data in the state?",{"type":414,"tag":415,"props":2463,"children":2464},{},[2465],{"type":419,"value":2466},"The state is transmitted and stored securely by Pulumi and whatever the backend you use you should restrict its access. For instance, in our example, you should have assigned the permissions on the storage account so that only the right people have access to it. Nevertheless, securing the state file is not enough because it contains sensitive data (keys, connection strings, ...) that you probably don't want anyone that has access to the file to be able to get.",{"type":414,"tag":415,"props":2468,"children":2469},{},[2470],{"type":419,"value":2471},"Indeed, it's not because a developer needs to read the state file to debug an issue that you want him to be able to see some production sensitive data in plain text in the state.  Having secrets in plain text in a state file would be like putting secrets in your source control and telling it is safe because only developers of the project team have access to it. Moreover, even if an unauthorized person succeeds to get access to the state file, it won't be an issue if all secrets in it are encrypted. Hence that is very nice to see Pulumi take security seriously and always encrypt sensitive information.",{"type":414,"tag":1506,"props":2473,"children":2475},{"id":2474},"what-are-the-available-encryption-providers",[2476],{"type":419,"value":2477},"What are the available encryption providers?",{"type":414,"tag":415,"props":2479,"children":2480},{},[2481],{"type":419,"value":2482},"As we have seen previously, when using a self-managed backend like Azure Blob Storage, by default Pulumi uses a passphrase to encrypt sensitive data.",{"type":414,"tag":415,"props":2484,"children":2485},{},[2486],{"type":419,"value":2487},"The passphrase is just one of the supported encryption/secrets providers but there are others:",{"type":414,"tag":1518,"props":2489,"children":2490},{},[2491,2496,2500,2505,2510],{"type":414,"tag":1522,"props":2492,"children":2493},{},[2494],{"type":419,"value":2495},"AWS Key Management Service",{"type":414,"tag":1522,"props":2497,"children":2498},{},[2499],{"type":419,"value":260},{"type":414,"tag":1522,"props":2501,"children":2502},{},[2503],{"type":419,"value":2504},"Google Cloud Key Management Service",{"type":414,"tag":1522,"props":2506,"children":2507},{},[2508],{"type":419,"value":2509},"HashiCorp Vault Transit Secrets Engine",{"type":414,"tag":1522,"props":2511,"children":2512},{},[2513],{"type":419,"value":2514},"Pulumi Service (used by default when using Pulumi Service as the backend)",{"type":414,"tag":415,"props":2516,"children":2517},{},[2518],{"type":419,"value":2519},"As for the backend, you don't have to use the default encryption provider and can come with your own resource. These providers can be used whatever the backend you chose, which lets you many possibilities. Now let's see how to use Azure Key Vault as our encryption provider.",{"type":414,"tag":1506,"props":2521,"children":2523},{"id":2522},"how-to-use-azure-key-vault-as-the-encryption-provider",[2524],{"type":419,"value":2525},"How to use Azure Key Vault as the encryption provider?",{"type":414,"tag":415,"props":2527,"children":2528},{},[2529],{"type":419,"value":2530},"Let's first create a Key Vault:",{"type":414,"tag":503,"props":2532,"children":2534},{"className":1758,"code":2533,"language":248,"meta":401,"style":401},"$kvName=\"kv-iacstate-westeu-$random\"\n$vaultId=az keyvault create -g $rgName -n $kvName --enable-rbac-authorization true --query \"id\"\n",[2535],{"type":414,"tag":479,"props":2536,"children":2537},{"__ignoreMap":401},[2538,2575],{"type":414,"tag":512,"props":2539,"children":2540},{"class":514,"line":515},[2541,2545,2550,2554,2558,2563,2567,2571],{"type":414,"tag":512,"props":2542,"children":2543},{"style":745},[2544],{"type":419,"value":1771},{"type":414,"tag":512,"props":2546,"children":2547},{"style":535},[2548],{"type":419,"value":2549},"kvName",{"type":414,"tag":512,"props":2551,"children":2552},{"style":745},[2553],{"type":419,"value":1781},{"type":414,"tag":512,"props":2555,"children":2556},{"style":745},[2557],{"type":419,"value":767},{"type":414,"tag":512,"props":2559,"children":2560},{"style":812},[2561],{"type":419,"value":2562},"kv-iacstate-westeu-",{"type":414,"tag":512,"props":2564,"children":2565},{"style":745},[2566],{"type":419,"value":1771},{"type":414,"tag":512,"props":2568,"children":2569},{"style":535},[2570],{"type":419,"value":1776},{"type":414,"tag":512,"props":2572,"children":2573},{"style":745},[2574],{"type":419,"value":897},{"type":414,"tag":512,"props":2576,"children":2577},{"class":514,"line":525},[2578,2582,2587,2591,2596,2600,2604,2608,2612,2616,2620,2624,2629,2633,2638,2642,2647,2651,2655,2659,2663],{"type":414,"tag":512,"props":2579,"children":2580},{"style":745},[2581],{"type":419,"value":1771},{"type":414,"tag":512,"props":2583,"children":2584},{"style":535},[2585],{"type":419,"value":2586},"vaultId",{"type":414,"tag":512,"props":2588,"children":2589},{"style":745},[2590],{"type":419,"value":1781},{"type":414,"tag":512,"props":2592,"children":2593},{"style":535},[2594],{"type":419,"value":2595},"az keyvault create ",{"type":414,"tag":512,"props":2597,"children":2598},{"style":745},[2599],{"type":419,"value":2137},{"type":414,"tag":512,"props":2601,"children":2602},{"style":535},[2603],{"type":419,"value":2160},{"type":414,"tag":512,"props":2605,"children":2606},{"style":745},[2607],{"type":419,"value":1771},{"type":414,"tag":512,"props":2609,"children":2610},{"style":535},[2611],{"type":419,"value":2169},{"type":414,"tag":512,"props":2613,"children":2614},{"style":745},[2615],{"type":419,"value":2137},{"type":414,"tag":512,"props":2617,"children":2618},{"style":535},[2619],{"type":419,"value":2142},{"type":414,"tag":512,"props":2621,"children":2622},{"style":745},[2623],{"type":419,"value":1771},{"type":414,"tag":512,"props":2625,"children":2626},{"style":535},[2627],{"type":419,"value":2628},"kvName ",{"type":414,"tag":512,"props":2630,"children":2631},{"style":745},[2632],{"type":419,"value":2183},{"type":414,"tag":512,"props":2634,"children":2635},{"style":1784},[2636],{"type":419,"value":2637},"enable-rbac",{"type":414,"tag":512,"props":2639,"children":2640},{"style":745},[2641],{"type":419,"value":2137},{"type":414,"tag":512,"props":2643,"children":2644},{"style":535},[2645],{"type":419,"value":2646},"authorization true ",{"type":414,"tag":512,"props":2648,"children":2649},{"style":745},[2650],{"type":419,"value":2183},{"type":414,"tag":512,"props":2652,"children":2653},{"style":535},[2654],{"type":419,"value":2188},{"type":414,"tag":512,"props":2656,"children":2657},{"style":745},[2658],{"type":419,"value":767},{"type":414,"tag":512,"props":2660,"children":2661},{"style":812},[2662],{"type":419,"value":1300},{"type":414,"tag":512,"props":2664,"children":2665},{"style":745},[2666],{"type":419,"value":897},{"type":414,"tag":415,"props":2668,"children":2669},{},[2670,2672,2678],{"type":419,"value":2671},"We retrieve its id so that we can use it to assign the correct role to my user to be able to perform cryptographic operations. With the ",{"type":414,"tag":479,"props":2673,"children":2675},{"className":2674},[],[2676],{"type":419,"value":2677},"--enable-rbac-authorization",{"type":419,"value":2679}," parameter we set the permissions model on the key vault to Role-Based Access Control but you can use the classic Vault access policies as well. I prefer using RBAC because I think it's more modern and more consistent with how we manage permissions on other Azure resources.",{"type":414,"tag":415,"props":2681,"children":2682},{},[2683],{"type":419,"value":2684},"To assign the appropriate permission to the current logged-in user, we will need its current identifier in Azure that we can retrieve with the following command:",{"type":414,"tag":503,"props":2686,"children":2688},{"className":1758,"code":2687,"language":248,"meta":401,"style":401},"$myUserId=az ad signed-in-user show --query \"objectId\" -o tsv \n",[2689],{"type":414,"tag":479,"props":2690,"children":2691},{"__ignoreMap":401},[2692],{"type":414,"tag":512,"props":2693,"children":2694},{"class":514,"line":515},[2695,2699,2704,2708,2713,2717,2722,2726,2731,2735,2739,2743,2748,2752,2756],{"type":414,"tag":512,"props":2696,"children":2697},{"style":745},[2698],{"type":419,"value":1771},{"type":414,"tag":512,"props":2700,"children":2701},{"style":535},[2702],{"type":419,"value":2703},"myUserId",{"type":414,"tag":512,"props":2705,"children":2706},{"style":745},[2707],{"type":419,"value":1781},{"type":414,"tag":512,"props":2709,"children":2710},{"style":535},[2711],{"type":419,"value":2712},"az ad signed",{"type":414,"tag":512,"props":2714,"children":2715},{"style":745},[2716],{"type":419,"value":2137},{"type":414,"tag":512,"props":2718,"children":2719},{"style":535},[2720],{"type":419,"value":2721},"in",{"type":414,"tag":512,"props":2723,"children":2724},{"style":745},[2725],{"type":419,"value":2137},{"type":414,"tag":512,"props":2727,"children":2728},{"style":535},[2729],{"type":419,"value":2730},"user show ",{"type":414,"tag":512,"props":2732,"children":2733},{"style":745},[2734],{"type":419,"value":2183},{"type":414,"tag":512,"props":2736,"children":2737},{"style":535},[2738],{"type":419,"value":2188},{"type":414,"tag":512,"props":2740,"children":2741},{"style":745},[2742],{"type":419,"value":767},{"type":414,"tag":512,"props":2744,"children":2745},{"style":812},[2746],{"type":419,"value":2747},"objectId",{"type":414,"tag":512,"props":2749,"children":2750},{"style":745},[2751],{"type":419,"value":767},{"type":414,"tag":512,"props":2753,"children":2754},{"style":745},[2755],{"type":419,"value":1376},{"type":414,"tag":512,"props":2757,"children":2758},{"style":535},[2759],{"type":419,"value":2760},"o tsv\n",{"type":414,"tag":415,"props":2762,"children":2763},{},[2764,2766,2772],{"type":419,"value":2765},"We can then assign to this user the ",{"type":414,"tag":479,"props":2767,"children":2769},{"className":2768},[],[2770],{"type":419,"value":2771},"Key Vault Crypto Officer",{"type":419,"value":2773}," role that will allow us to create a key and encrypt/decrypt data.",{"type":414,"tag":503,"props":2775,"children":2777},{"className":1758,"code":2776,"language":248,"meta":401,"style":401},"az role assignment create --scope $vaultId --role \"Key Vault Crypto Officer\" --assignee $myUserId \n",[2778],{"type":414,"tag":479,"props":2779,"children":2780},{"__ignoreMap":401},[2781],{"type":414,"tag":512,"props":2782,"children":2783},{"class":514,"line":515},[2784,2789,2793,2798,2802,2807,2811,2816,2820,2824,2828,2832,2837,2841],{"type":414,"tag":512,"props":2785,"children":2786},{"style":535},[2787],{"type":419,"value":2788},"az role assignment create ",{"type":414,"tag":512,"props":2790,"children":2791},{"style":745},[2792],{"type":419,"value":2183},{"type":414,"tag":512,"props":2794,"children":2795},{"style":535},[2796],{"type":419,"value":2797},"scope ",{"type":414,"tag":512,"props":2799,"children":2800},{"style":745},[2801],{"type":419,"value":1771},{"type":414,"tag":512,"props":2803,"children":2804},{"style":535},[2805],{"type":419,"value":2806},"vaultId ",{"type":414,"tag":512,"props":2808,"children":2809},{"style":745},[2810],{"type":419,"value":2183},{"type":414,"tag":512,"props":2812,"children":2813},{"style":535},[2814],{"type":419,"value":2815},"role ",{"type":414,"tag":512,"props":2817,"children":2818},{"style":745},[2819],{"type":419,"value":767},{"type":414,"tag":512,"props":2821,"children":2822},{"style":812},[2823],{"type":419,"value":2771},{"type":414,"tag":512,"props":2825,"children":2826},{"style":745},[2827],{"type":419,"value":767},{"type":414,"tag":512,"props":2829,"children":2830},{"style":745},[2831],{"type":419,"value":1213},{"type":414,"tag":512,"props":2833,"children":2834},{"style":535},[2835],{"type":419,"value":2836},"assignee ",{"type":414,"tag":512,"props":2838,"children":2839},{"style":745},[2840],{"type":419,"value":1771},{"type":414,"tag":512,"props":2842,"children":2843},{"style":535},[2844],{"type":419,"value":2845},"myUserId\n",{"type":414,"tag":415,"props":2847,"children":2848},{},[2849],{"type":419,"value":2850},"The key to encrypt/decrypt data can be created with the following command:",{"type":414,"tag":503,"props":2852,"children":2854},{"className":1758,"code":2853,"language":248,"meta":401,"style":401},"az keyvault key create -n encryptionState --vault-name $kvName\n",[2855],{"type":414,"tag":479,"props":2856,"children":2857},{"__ignoreMap":401},[2858],{"type":414,"tag":512,"props":2859,"children":2860},{"class":514,"line":515},[2861,2866,2870,2875,2879,2884,2888,2893,2897],{"type":414,"tag":512,"props":2862,"children":2863},{"style":535},[2864],{"type":419,"value":2865},"az keyvault key create ",{"type":414,"tag":512,"props":2867,"children":2868},{"style":745},[2869],{"type":419,"value":2137},{"type":414,"tag":512,"props":2871,"children":2872},{"style":535},[2873],{"type":419,"value":2874},"n encryptionState ",{"type":414,"tag":512,"props":2876,"children":2877},{"style":745},[2878],{"type":419,"value":2183},{"type":414,"tag":512,"props":2880,"children":2881},{"style":535},[2882],{"type":419,"value":2883},"vault",{"type":414,"tag":512,"props":2885,"children":2886},{"style":745},[2887],{"type":419,"value":2137},{"type":414,"tag":512,"props":2889,"children":2890},{"style":535},[2891],{"type":419,"value":2892},"name ",{"type":414,"tag":512,"props":2894,"children":2895},{"style":745},[2896],{"type":419,"value":1771},{"type":414,"tag":512,"props":2898,"children":2899},{"style":535},[2900],{"type":419,"value":2901},"kvName\n",{"type":414,"tag":415,"props":2903,"children":2904},{},[2905],{"type":419,"value":2906},"By default, Pulumi CLI will try to use environment variables to authenticate to the key vault, so we need to tell it to use the Azure CLI instead as we gave the permission on the key vault to the user currently logged in:",{"type":414,"tag":503,"props":2908,"children":2910},{"className":1758,"code":2909,"language":248,"meta":401,"style":401},"$env:AZURE_KEYVAULT_AUTH_VIA_CLI=\"true\"\n",[2911],{"type":414,"tag":479,"props":2912,"children":2913},{"__ignoreMap":401},[2914],{"type":414,"tag":512,"props":2915,"children":2916},{"class":514,"line":515},[2917,2921,2926,2930,2934,2939],{"type":414,"tag":512,"props":2918,"children":2919},{"style":745},[2920],{"type":419,"value":1771},{"type":414,"tag":512,"props":2922,"children":2923},{"style":535},[2924],{"type":419,"value":2925},"env:AZURE_KEYVAULT_AUTH_VIA_CLI",{"type":414,"tag":512,"props":2927,"children":2928},{"style":745},[2929],{"type":419,"value":1781},{"type":414,"tag":512,"props":2931,"children":2932},{"style":745},[2933],{"type":419,"value":767},{"type":414,"tag":512,"props":2935,"children":2936},{"style":812},[2937],{"type":419,"value":2938},"true",{"type":414,"tag":512,"props":2940,"children":2941},{"style":745},[2942],{"type":419,"value":897},{"type":414,"tag":415,"props":2944,"children":2945},{},[2946],{"type":419,"value":2947},"Now that everything is configured, we can modify our previous command to create a new Pulumi project by specifying the encryption provider to use:",{"type":414,"tag":503,"props":2949,"children":2951},{"className":1758,"code":2950,"language":248,"meta":401,"style":401},"pulumi new azure-csharp -n AzureStorageBackend -s dev -y --secrets-provider=\"azurekeyvault://$kvName.vault.azure.net/keys/encryptionState\"\n",[2952],{"type":414,"tag":479,"props":2953,"children":2954},{"__ignoreMap":401},[2955],{"type":414,"tag":512,"props":2956,"children":2957},{"class":514,"line":515},[2958,2962,2966,2970,2974,2978,2982,2986,2990,2995,2999,3004,3008,3013,3017,3021,3026,3030,3034,3039],{"type":414,"tag":512,"props":2959,"children":2960},{"style":535},[2961],{"type":419,"value":2363},{"type":414,"tag":512,"props":2963,"children":2964},{"style":745},[2965],{"type":419,"value":2137},{"type":414,"tag":512,"props":2967,"children":2968},{"style":535},[2969],{"type":419,"value":2372},{"type":414,"tag":512,"props":2971,"children":2972},{"style":745},[2973],{"type":419,"value":2137},{"type":414,"tag":512,"props":2975,"children":2976},{"style":535},[2977],{"type":419,"value":2381},{"type":414,"tag":512,"props":2979,"children":2980},{"style":745},[2981],{"type":419,"value":2137},{"type":414,"tag":512,"props":2983,"children":2984},{"style":535},[2985],{"type":419,"value":2390},{"type":414,"tag":512,"props":2987,"children":2988},{"style":745},[2989],{"type":419,"value":2137},{"type":414,"tag":512,"props":2991,"children":2992},{"style":535},[2993],{"type":419,"value":2994},"y ",{"type":414,"tag":512,"props":2996,"children":2997},{"style":745},[2998],{"type":419,"value":2183},{"type":414,"tag":512,"props":3000,"children":3001},{"style":535},[3002],{"type":419,"value":3003},"secrets",{"type":414,"tag":512,"props":3005,"children":3006},{"style":745},[3007],{"type":419,"value":2137},{"type":414,"tag":512,"props":3009,"children":3010},{"style":535},[3011],{"type":419,"value":3012},"provider",{"type":414,"tag":512,"props":3014,"children":3015},{"style":745},[3016],{"type":419,"value":1781},{"type":414,"tag":512,"props":3018,"children":3019},{"style":745},[3020],{"type":419,"value":767},{"type":414,"tag":512,"props":3022,"children":3023},{"style":812},[3024],{"type":419,"value":3025},"azurekeyvault://",{"type":414,"tag":512,"props":3027,"children":3028},{"style":745},[3029],{"type":419,"value":1771},{"type":414,"tag":512,"props":3031,"children":3032},{"style":535},[3033],{"type":419,"value":2549},{"type":414,"tag":512,"props":3035,"children":3036},{"style":812},[3037],{"type":419,"value":3038},".vault.azure.net/keys/encryptionState",{"type":414,"tag":512,"props":3040,"children":3041},{"style":745},[3042],{"type":419,"value":897},{"type":414,"tag":459,"props":3044,"children":3046},{"id":3045},"comparing-with-how-terraform-handle-state",[3047],{"type":419,"value":3048},"Comparing with how Terraform handle state",{"type":414,"tag":415,"props":3050,"children":3051},{},[3052],{"type":419,"value":3053},"Terraform is another very popular Infrastructure as Code platform with lots of similarities so I thought it might be interesting to look at how Terraform handles state compared to Pulumi.",{"type":414,"tag":415,"props":3055,"children":3056},{},[3057],{"type":419,"value":3058},"Terraform has a SaaS platform called Terraform Cloud that can be used to manage the infrastructure state. It is similar to what Pulumi Service offers. However, when using Terraform the default backend is not Terraform Cloud but local filesystem. That is not better or worse, just a different choice HashiCorp (the company behind Terraform) did. Although I must say that when I started working on Pulumi, I found it easier not having to take care of where the state is stored and how it is managed, so maybe a SaaS backend by default is simpler.",{"type":414,"tag":415,"props":3060,"children":3061},{},[3062,3064,3071],{"type":419,"value":3063},"On Microsoft documentation, there is a tutorial ",{"type":414,"tag":422,"props":3065,"children":3068},{"href":3066,"rel":3067},"https://docs.microsoft.com/en-us/azure/developer/terraform/store-state-in-azure-storage",[426],[3069],{"type":419,"value":3070},"\"Store Terraform state in Azure Storage\"",{"type":419,"value":3072}," that shows how to use Terraform with an Azure Storage backend. I have done it and it is very similar to what we have done in this article with Pulumi. Instead of using a CLI command to configure the infrastructure to use Azure Blob Storage as the backend for the state, in Terraform, you configure it directly in one of the code files but the idea is the same. Both IaC tools store the infrastructure state in a JSON file in a blob container.",{"type":414,"tag":415,"props":3074,"children":3075},{},[3076,3078,3085,3087,3093],{"type":419,"value":3077},"One big difference however is that by default Terraform does not encrypt sensitive information in the state file. As far as I know, there is no concept of secret providers in Terraform so no built-in solution. ",{"type":414,"tag":422,"props":3079,"children":3082},{"href":3080,"rel":3081},"https://www.terraform.io/docs/language/state/sensitive-data.html",[426],[3083],{"type":419,"value":3084},"Terraform documentation",{"type":419,"value":3086}," just says to ",{"type":414,"tag":479,"props":3088,"children":3090},{"className":3089},[],[3091],{"type":419,"value":3092},"treat the state itself as sensitive data",{"type":419,"value":3094},". That means when I created a storage account using Terraform with the Azure Blob Storage backend, the keys of my storage were available in plain text in my state file (as you can see in the image below).",{"type":414,"tag":415,"props":3096,"children":3097},{},[3098],{"type":414,"tag":609,"props":3099,"children":3103},{"alt":3100,"className":3101,"src":3102},"Terraform state file containing clear text sensitive information in vscode.",[613,614],"/posts/images/pulumiazurebackend_tf_1.png",[],{"type":414,"tag":415,"props":3105,"children":3106},{},[3107],{"type":419,"value":3108},"You should not have this kind of security issue using Terraform Cloud and there are probably external tools to avoid this, but I think an IaC platform should be secure by default and that encryption of sensitive data should be built-in.",{"type":414,"tag":459,"props":3110,"children":3112},{"id":3111},"to-conclude",[3113],{"type":419,"value":3114},"To conclude",{"type":414,"tag":415,"props":3116,"children":3117},{},[3118],{"type":419,"value":3119},"You can find below the complete Azure CLI script used in this article:",{"type":414,"tag":503,"props":3121,"children":3123},{"className":1758,"code":3122,"language":248,"meta":401,"style":401},"# PowerShell variables used in the script \n$random=Get-Random -Maximum 1000\n$location=\"West Europe\"\n$rgName=\"rg-iacstate-westeu-$random\"\n$saName=\"stiacstate$random\"\n$kvName=\"kv-iacstate-westeu-$random\"\n\naz group create -n $rgName -l $location\n\n# Configure the Azure Blob Storage that will contain the state \naz storage account create -g $rgName -n $saName -l $location --sku Standard_LRS\n# Set environment variables needed to write on the storage account\n$env:AZURE_STORAGE_KEY=$(az storage account keys list -n $saName -g $rgName -o tsv --query '[0].value')\n$env:AZURE_STORAGE_ACCOUNT=$saName\naz storage container create -n iacstate\n\n# Configure the Key Vault that will be used to encrypt the sensitive data\n$vaultId=az keyvault create -g $rgName -n $kvName --enable-rbac-authorization true --query \"id\"\n$myUserId=az ad signed-in-user show --query \"objectId\" -o tsv \naz role assignment create --scope $vaultId --role \"Key Vault Crypto Officer\" --assignee $myUserId \naz keyvault key create -n encryptionState --vault-name $kvName\n# Use az cli to authenticate to key vault instead of using environment variables \n$env:AZURE_KEYVAULT_AUTH_VIA_CLI=\"true\"\n\n# Indicate pulumi to use the newly created azure blob storage as a backend\npulumi login azblob://iacstate\n# Create and use a folder to store the infrastructure code\nmkdir infra;cd infra;\n# Create a new Pulumi project using the azure blob storage as the backend and the keyvault as the encryption provider \npulumi new azure-csharp -n AzureStorageBackend -s dev -y --secrets-provider=\"azurekeyvault://$kvName.vault.azure.net/keys/encryptionState\"\n# Deploy the infrastructure\npulumi up -y\n",[3124],{"type":414,"tag":479,"props":3125,"children":3126},{"__ignoreMap":401},[3127,3135,3166,3193,3228,3263,3298,3307,3349,3356,3365,3432,3441,3525,3545,3563,3571,3580,3668,3733,3794,3834,3843,3871,3879,3888,3904,3913,3933,3942,4026,4035],{"type":414,"tag":512,"props":3128,"children":3129},{"class":514,"line":515},[3130],{"type":414,"tag":512,"props":3131,"children":3132},{"style":519},[3133],{"type":419,"value":3134},"# PowerShell variables used in the script \n",{"type":414,"tag":512,"props":3136,"children":3137},{"class":514,"line":525},[3138,3142,3146,3150,3154,3158,3162],{"type":414,"tag":512,"props":3139,"children":3140},{"style":745},[3141],{"type":419,"value":1771},{"type":414,"tag":512,"props":3143,"children":3144},{"style":535},[3145],{"type":419,"value":1776},{"type":414,"tag":512,"props":3147,"children":3148},{"style":745},[3149],{"type":419,"value":1781},{"type":414,"tag":512,"props":3151,"children":3152},{"style":1784},[3153],{"type":419,"value":1787},{"type":414,"tag":512,"props":3155,"children":3156},{"style":745},[3157],{"type":419,"value":1376},{"type":414,"tag":512,"props":3159,"children":3160},{"style":535},[3161],{"type":419,"value":1796},{"type":414,"tag":512,"props":3163,"children":3164},{"style":541},[3165],{"type":419,"value":1801},{"type":414,"tag":512,"props":3167,"children":3168},{"class":514,"line":775},[3169,3173,3177,3181,3185,3189],{"type":414,"tag":512,"props":3170,"children":3171},{"style":745},[3172],{"type":419,"value":1771},{"type":414,"tag":512,"props":3174,"children":3175},{"style":535},[3176],{"type":419,"value":1813},{"type":414,"tag":512,"props":3178,"children":3179},{"style":745},[3180],{"type":419,"value":1781},{"type":414,"tag":512,"props":3182,"children":3183},{"style":745},[3184],{"type":419,"value":767},{"type":414,"tag":512,"props":3186,"children":3187},{"style":812},[3188],{"type":419,"value":1826},{"type":414,"tag":512,"props":3190,"children":3191},{"style":745},[3192],{"type":419,"value":897},{"type":414,"tag":512,"props":3194,"children":3195},{"class":514,"line":784},[3196,3200,3204,3208,3212,3216,3220,3224],{"type":414,"tag":512,"props":3197,"children":3198},{"style":745},[3199],{"type":419,"value":1771},{"type":414,"tag":512,"props":3201,"children":3202},{"style":535},[3203],{"type":419,"value":1842},{"type":414,"tag":512,"props":3205,"children":3206},{"style":745},[3207],{"type":419,"value":1781},{"type":414,"tag":512,"props":3209,"children":3210},{"style":745},[3211],{"type":419,"value":767},{"type":414,"tag":512,"props":3213,"children":3214},{"style":812},[3215],{"type":419,"value":1855},{"type":414,"tag":512,"props":3217,"children":3218},{"style":745},[3219],{"type":419,"value":1771},{"type":414,"tag":512,"props":3221,"children":3222},{"style":535},[3223],{"type":419,"value":1776},{"type":414,"tag":512,"props":3225,"children":3226},{"style":745},[3227],{"type":419,"value":897},{"type":414,"tag":512,"props":3229,"children":3230},{"class":514,"line":827},[3231,3235,3239,3243,3247,3251,3255,3259],{"type":414,"tag":512,"props":3232,"children":3233},{"style":745},[3234],{"type":419,"value":1771},{"type":414,"tag":512,"props":3236,"children":3237},{"style":535},[3238],{"type":419,"value":1879},{"type":414,"tag":512,"props":3240,"children":3241},{"style":745},[3242],{"type":419,"value":1781},{"type":414,"tag":512,"props":3244,"children":3245},{"style":745},[3246],{"type":419,"value":767},{"type":414,"tag":512,"props":3248,"children":3249},{"style":812},[3250],{"type":419,"value":1892},{"type":414,"tag":512,"props":3252,"children":3253},{"style":745},[3254],{"type":419,"value":1771},{"type":414,"tag":512,"props":3256,"children":3257},{"style":535},[3258],{"type":419,"value":1776},{"type":414,"tag":512,"props":3260,"children":3261},{"style":745},[3262],{"type":419,"value":897},{"type":414,"tag":512,"props":3264,"children":3265},{"class":514,"line":865},[3266,3270,3274,3278,3282,3286,3290,3294],{"type":414,"tag":512,"props":3267,"children":3268},{"style":745},[3269],{"type":419,"value":1771},{"type":414,"tag":512,"props":3271,"children":3272},{"style":535},[3273],{"type":419,"value":2549},{"type":414,"tag":512,"props":3275,"children":3276},{"style":745},[3277],{"type":419,"value":1781},{"type":414,"tag":512,"props":3279,"children":3280},{"style":745},[3281],{"type":419,"value":767},{"type":414,"tag":512,"props":3283,"children":3284},{"style":812},[3285],{"type":419,"value":2562},{"type":414,"tag":512,"props":3287,"children":3288},{"style":745},[3289],{"type":419,"value":1771},{"type":414,"tag":512,"props":3291,"children":3292},{"style":535},[3293],{"type":419,"value":1776},{"type":414,"tag":512,"props":3295,"children":3296},{"style":745},[3297],{"type":419,"value":897},{"type":414,"tag":512,"props":3299,"children":3300},{"class":514,"line":900},[3301],{"type":414,"tag":512,"props":3302,"children":3304},{"emptyLinePlaceholder":3303},true,[3305],{"type":419,"value":3306},"\n",{"type":414,"tag":512,"props":3308,"children":3309},{"class":514,"line":909},[3310,3315,3319,3323,3327,3331,3335,3340,3344],{"type":414,"tag":512,"props":3311,"children":3312},{"style":535},[3313],{"type":419,"value":3314},"az group create ",{"type":414,"tag":512,"props":3316,"children":3317},{"style":745},[3318],{"type":419,"value":2137},{"type":414,"tag":512,"props":3320,"children":3321},{"style":535},[3322],{"type":419,"value":2142},{"type":414,"tag":512,"props":3324,"children":3325},{"style":745},[3326],{"type":419,"value":1771},{"type":414,"tag":512,"props":3328,"children":3329},{"style":535},[3330],{"type":419,"value":2169},{"type":414,"tag":512,"props":3332,"children":3333},{"style":745},[3334],{"type":419,"value":2137},{"type":414,"tag":512,"props":3336,"children":3337},{"style":535},[3338],{"type":419,"value":3339},"l ",{"type":414,"tag":512,"props":3341,"children":3342},{"style":745},[3343],{"type":419,"value":1771},{"type":414,"tag":512,"props":3345,"children":3346},{"style":535},[3347],{"type":419,"value":3348},"location\n",{"type":414,"tag":512,"props":3350,"children":3351},{"class":514,"line":1431},[3352],{"type":414,"tag":512,"props":3353,"children":3354},{"emptyLinePlaceholder":3303},[3355],{"type":419,"value":3306},{"type":414,"tag":512,"props":3357,"children":3359},{"class":514,"line":3358},10,[3360],{"type":414,"tag":512,"props":3361,"children":3362},{"style":519},[3363],{"type":419,"value":3364},"# Configure the Azure Blob Storage that will contain the state \n",{"type":414,"tag":512,"props":3366,"children":3368},{"class":514,"line":3367},11,[3369,3374,3378,3382,3386,3390,3394,3398,3402,3406,3410,3414,3418,3423,3427],{"type":414,"tag":512,"props":3370,"children":3371},{"style":535},[3372],{"type":419,"value":3373},"az storage account create ",{"type":414,"tag":512,"props":3375,"children":3376},{"style":745},[3377],{"type":419,"value":2137},{"type":414,"tag":512,"props":3379,"children":3380},{"style":535},[3381],{"type":419,"value":2160},{"type":414,"tag":512,"props":3383,"children":3384},{"style":745},[3385],{"type":419,"value":1771},{"type":414,"tag":512,"props":3387,"children":3388},{"style":535},[3389],{"type":419,"value":2169},{"type":414,"tag":512,"props":3391,"children":3392},{"style":745},[3393],{"type":419,"value":2137},{"type":414,"tag":512,"props":3395,"children":3396},{"style":535},[3397],{"type":419,"value":2142},{"type":414,"tag":512,"props":3399,"children":3400},{"style":745},[3401],{"type":419,"value":1771},{"type":414,"tag":512,"props":3403,"children":3404},{"style":535},[3405],{"type":419,"value":2151},{"type":414,"tag":512,"props":3407,"children":3408},{"style":745},[3409],{"type":419,"value":2137},{"type":414,"tag":512,"props":3411,"children":3412},{"style":535},[3413],{"type":419,"value":3339},{"type":414,"tag":512,"props":3415,"children":3416},{"style":745},[3417],{"type":419,"value":1771},{"type":414,"tag":512,"props":3419,"children":3420},{"style":535},[3421],{"type":419,"value":3422},"location ",{"type":414,"tag":512,"props":3424,"children":3425},{"style":745},[3426],{"type":419,"value":2183},{"type":414,"tag":512,"props":3428,"children":3429},{"style":535},[3430],{"type":419,"value":3431},"sku Standard_LRS\n",{"type":414,"tag":512,"props":3433,"children":3435},{"class":514,"line":3434},12,[3436],{"type":414,"tag":512,"props":3437,"children":3438},{"style":519},[3439],{"type":419,"value":3440},"# Set environment variables needed to write on the storage account\n",{"type":414,"tag":512,"props":3442,"children":3444},{"class":514,"line":3443},13,[3445,3449,3453,3457,3461,3465,3469,3473,3477,3481,3485,3489,3493,3497,3501,3505,3509,3513,3517,3521],{"type":414,"tag":512,"props":3446,"children":3447},{"style":745},[3448],{"type":419,"value":1771},{"type":414,"tag":512,"props":3450,"children":3451},{"style":535},[3452],{"type":419,"value":2122},{"type":414,"tag":512,"props":3454,"children":3455},{"style":745},[3456],{"type":419,"value":2127},{"type":414,"tag":512,"props":3458,"children":3459},{"style":535},[3460],{"type":419,"value":2132},{"type":414,"tag":512,"props":3462,"children":3463},{"style":745},[3464],{"type":419,"value":2137},{"type":414,"tag":512,"props":3466,"children":3467},{"style":535},[3468],{"type":419,"value":2142},{"type":414,"tag":512,"props":3470,"children":3471},{"style":745},[3472],{"type":419,"value":1771},{"type":414,"tag":512,"props":3474,"children":3475},{"style":535},[3476],{"type":419,"value":2151},{"type":414,"tag":512,"props":3478,"children":3479},{"style":745},[3480],{"type":419,"value":2137},{"type":414,"tag":512,"props":3482,"children":3483},{"style":535},[3484],{"type":419,"value":2160},{"type":414,"tag":512,"props":3486,"children":3487},{"style":745},[3488],{"type":419,"value":1771},{"type":414,"tag":512,"props":3490,"children":3491},{"style":535},[3492],{"type":419,"value":2169},{"type":414,"tag":512,"props":3494,"children":3495},{"style":745},[3496],{"type":419,"value":2137},{"type":414,"tag":512,"props":3498,"children":3499},{"style":535},[3500],{"type":419,"value":2178},{"type":414,"tag":512,"props":3502,"children":3503},{"style":745},[3504],{"type":419,"value":2183},{"type":414,"tag":512,"props":3506,"children":3507},{"style":535},[3508],{"type":419,"value":2188},{"type":414,"tag":512,"props":3510,"children":3511},{"style":745},[3512],{"type":419,"value":2193},{"type":414,"tag":512,"props":3514,"children":3515},{"style":812},[3516],{"type":419,"value":2093},{"type":414,"tag":512,"props":3518,"children":3519},{"style":745},[3520],{"type":419,"value":2193},{"type":414,"tag":512,"props":3522,"children":3523},{"style":745},[3524],{"type":419,"value":1437},{"type":414,"tag":512,"props":3526,"children":3528},{"class":514,"line":3527},14,[3529,3533,3537,3541],{"type":414,"tag":512,"props":3530,"children":3531},{"style":745},[3532],{"type":419,"value":1771},{"type":414,"tag":512,"props":3534,"children":3535},{"style":535},[3536],{"type":419,"value":2217},{"type":414,"tag":512,"props":3538,"children":3539},{"style":745},[3540],{"type":419,"value":2222},{"type":414,"tag":512,"props":3542,"children":3543},{"style":535},[3544],{"type":419,"value":2227},{"type":414,"tag":512,"props":3546,"children":3548},{"class":514,"line":3547},15,[3549,3554,3558],{"type":414,"tag":512,"props":3550,"children":3551},{"style":535},[3552],{"type":419,"value":3553},"az storage container create ",{"type":414,"tag":512,"props":3555,"children":3556},{"style":745},[3557],{"type":419,"value":2137},{"type":414,"tag":512,"props":3559,"children":3560},{"style":535},[3561],{"type":419,"value":3562},"n iacstate\n",{"type":414,"tag":512,"props":3564,"children":3566},{"class":514,"line":3565},16,[3567],{"type":414,"tag":512,"props":3568,"children":3569},{"emptyLinePlaceholder":3303},[3570],{"type":419,"value":3306},{"type":414,"tag":512,"props":3572,"children":3574},{"class":514,"line":3573},17,[3575],{"type":414,"tag":512,"props":3576,"children":3577},{"style":519},[3578],{"type":419,"value":3579},"# Configure the Key Vault that will be used to encrypt the sensitive data\n",{"type":414,"tag":512,"props":3581,"children":3583},{"class":514,"line":3582},18,[3584,3588,3592,3596,3600,3604,3608,3612,3616,3620,3624,3628,3632,3636,3640,3644,3648,3652,3656,3660,3664],{"type":414,"tag":512,"props":3585,"children":3586},{"style":745},[3587],{"type":419,"value":1771},{"type":414,"tag":512,"props":3589,"children":3590},{"style":535},[3591],{"type":419,"value":2586},{"type":414,"tag":512,"props":3593,"children":3594},{"style":745},[3595],{"type":419,"value":1781},{"type":414,"tag":512,"props":3597,"children":3598},{"style":535},[3599],{"type":419,"value":2595},{"type":414,"tag":512,"props":3601,"children":3602},{"style":745},[3603],{"type":419,"value":2137},{"type":414,"tag":512,"props":3605,"children":3606},{"style":535},[3607],{"type":419,"value":2160},{"type":414,"tag":512,"props":3609,"children":3610},{"style":745},[3611],{"type":419,"value":1771},{"type":414,"tag":512,"props":3613,"children":3614},{"style":535},[3615],{"type":419,"value":2169},{"type":414,"tag":512,"props":3617,"children":3618},{"style":745},[3619],{"type":419,"value":2137},{"type":414,"tag":512,"props":3621,"children":3622},{"style":535},[3623],{"type":419,"value":2142},{"type":414,"tag":512,"props":3625,"children":3626},{"style":745},[3627],{"type":419,"value":1771},{"type":414,"tag":512,"props":3629,"children":3630},{"style":535},[3631],{"type":419,"value":2628},{"type":414,"tag":512,"props":3633,"children":3634},{"style":745},[3635],{"type":419,"value":2183},{"type":414,"tag":512,"props":3637,"children":3638},{"style":1784},[3639],{"type":419,"value":2637},{"type":414,"tag":512,"props":3641,"children":3642},{"style":745},[3643],{"type":419,"value":2137},{"type":414,"tag":512,"props":3645,"children":3646},{"style":535},[3647],{"type":419,"value":2646},{"type":414,"tag":512,"props":3649,"children":3650},{"style":745},[3651],{"type":419,"value":2183},{"type":414,"tag":512,"props":3653,"children":3654},{"style":535},[3655],{"type":419,"value":2188},{"type":414,"tag":512,"props":3657,"children":3658},{"style":745},[3659],{"type":419,"value":767},{"type":414,"tag":512,"props":3661,"children":3662},{"style":812},[3663],{"type":419,"value":1300},{"type":414,"tag":512,"props":3665,"children":3666},{"style":745},[3667],{"type":419,"value":897},{"type":414,"tag":512,"props":3669,"children":3671},{"class":514,"line":3670},19,[3672,3676,3680,3684,3688,3692,3696,3700,3704,3708,3712,3716,3720,3724,3728],{"type":414,"tag":512,"props":3673,"children":3674},{"style":745},[3675],{"type":419,"value":1771},{"type":414,"tag":512,"props":3677,"children":3678},{"style":535},[3679],{"type":419,"value":2703},{"type":414,"tag":512,"props":3681,"children":3682},{"style":745},[3683],{"type":419,"value":1781},{"type":414,"tag":512,"props":3685,"children":3686},{"style":535},[3687],{"type":419,"value":2712},{"type":414,"tag":512,"props":3689,"children":3690},{"style":745},[3691],{"type":419,"value":2137},{"type":414,"tag":512,"props":3693,"children":3694},{"style":535},[3695],{"type":419,"value":2721},{"type":414,"tag":512,"props":3697,"children":3698},{"style":745},[3699],{"type":419,"value":2137},{"type":414,"tag":512,"props":3701,"children":3702},{"style":535},[3703],{"type":419,"value":2730},{"type":414,"tag":512,"props":3705,"children":3706},{"style":745},[3707],{"type":419,"value":2183},{"type":414,"tag":512,"props":3709,"children":3710},{"style":535},[3711],{"type":419,"value":2188},{"type":414,"tag":512,"props":3713,"children":3714},{"style":745},[3715],{"type":419,"value":767},{"type":414,"tag":512,"props":3717,"children":3718},{"style":812},[3719],{"type":419,"value":2747},{"type":414,"tag":512,"props":3721,"children":3722},{"style":745},[3723],{"type":419,"value":767},{"type":414,"tag":512,"props":3725,"children":3726},{"style":745},[3727],{"type":419,"value":1376},{"type":414,"tag":512,"props":3729,"children":3730},{"style":535},[3731],{"type":419,"value":3732},"o tsv \n",{"type":414,"tag":512,"props":3734,"children":3736},{"class":514,"line":3735},20,[3737,3741,3745,3749,3753,3757,3761,3765,3769,3773,3777,3781,3785,3789],{"type":414,"tag":512,"props":3738,"children":3739},{"style":535},[3740],{"type":419,"value":2788},{"type":414,"tag":512,"props":3742,"children":3743},{"style":745},[3744],{"type":419,"value":2183},{"type":414,"tag":512,"props":3746,"children":3747},{"style":535},[3748],{"type":419,"value":2797},{"type":414,"tag":512,"props":3750,"children":3751},{"style":745},[3752],{"type":419,"value":1771},{"type":414,"tag":512,"props":3754,"children":3755},{"style":535},[3756],{"type":419,"value":2806},{"type":414,"tag":512,"props":3758,"children":3759},{"style":745},[3760],{"type":419,"value":2183},{"type":414,"tag":512,"props":3762,"children":3763},{"style":535},[3764],{"type":419,"value":2815},{"type":414,"tag":512,"props":3766,"children":3767},{"style":745},[3768],{"type":419,"value":767},{"type":414,"tag":512,"props":3770,"children":3771},{"style":812},[3772],{"type":419,"value":2771},{"type":414,"tag":512,"props":3774,"children":3775},{"style":745},[3776],{"type":419,"value":767},{"type":414,"tag":512,"props":3778,"children":3779},{"style":745},[3780],{"type":419,"value":1213},{"type":414,"tag":512,"props":3782,"children":3783},{"style":535},[3784],{"type":419,"value":2836},{"type":414,"tag":512,"props":3786,"children":3787},{"style":745},[3788],{"type":419,"value":1771},{"type":414,"tag":512,"props":3790,"children":3791},{"style":535},[3792],{"type":419,"value":3793},"myUserId \n",{"type":414,"tag":512,"props":3795,"children":3797},{"class":514,"line":3796},21,[3798,3802,3806,3810,3814,3818,3822,3826,3830],{"type":414,"tag":512,"props":3799,"children":3800},{"style":535},[3801],{"type":419,"value":2865},{"type":414,"tag":512,"props":3803,"children":3804},{"style":745},[3805],{"type":419,"value":2137},{"type":414,"tag":512,"props":3807,"children":3808},{"style":535},[3809],{"type":419,"value":2874},{"type":414,"tag":512,"props":3811,"children":3812},{"style":745},[3813],{"type":419,"value":2183},{"type":414,"tag":512,"props":3815,"children":3816},{"style":535},[3817],{"type":419,"value":2883},{"type":414,"tag":512,"props":3819,"children":3820},{"style":745},[3821],{"type":419,"value":2137},{"type":414,"tag":512,"props":3823,"children":3824},{"style":535},[3825],{"type":419,"value":2892},{"type":414,"tag":512,"props":3827,"children":3828},{"style":745},[3829],{"type":419,"value":1771},{"type":414,"tag":512,"props":3831,"children":3832},{"style":535},[3833],{"type":419,"value":2901},{"type":414,"tag":512,"props":3835,"children":3837},{"class":514,"line":3836},22,[3838],{"type":414,"tag":512,"props":3839,"children":3840},{"style":519},[3841],{"type":419,"value":3842},"# Use az cli to authenticate to key vault instead of using environment variables \n",{"type":414,"tag":512,"props":3844,"children":3846},{"class":514,"line":3845},23,[3847,3851,3855,3859,3863,3867],{"type":414,"tag":512,"props":3848,"children":3849},{"style":745},[3850],{"type":419,"value":1771},{"type":414,"tag":512,"props":3852,"children":3853},{"style":535},[3854],{"type":419,"value":2925},{"type":414,"tag":512,"props":3856,"children":3857},{"style":745},[3858],{"type":419,"value":1781},{"type":414,"tag":512,"props":3860,"children":3861},{"style":745},[3862],{"type":419,"value":767},{"type":414,"tag":512,"props":3864,"children":3865},{"style":812},[3866],{"type":419,"value":2938},{"type":414,"tag":512,"props":3868,"children":3869},{"style":745},[3870],{"type":419,"value":897},{"type":414,"tag":512,"props":3872,"children":3874},{"class":514,"line":3873},24,[3875],{"type":414,"tag":512,"props":3876,"children":3877},{"emptyLinePlaceholder":3303},[3878],{"type":419,"value":3306},{"type":414,"tag":512,"props":3880,"children":3882},{"class":514,"line":3881},25,[3883],{"type":414,"tag":512,"props":3884,"children":3885},{"style":519},[3886],{"type":419,"value":3887},"# Indicate pulumi to use the newly created azure blob storage as a backend\n",{"type":414,"tag":512,"props":3889,"children":3891},{"class":514,"line":3890},26,[3892,3896,3900],{"type":414,"tag":512,"props":3893,"children":3894},{"style":535},[3895],{"type":419,"value":2294},{"type":414,"tag":512,"props":3897,"children":3898},{"style":745},[3899],{"type":419,"value":2299},{"type":414,"tag":512,"props":3901,"children":3902},{"style":535},[3903],{"type":419,"value":2304},{"type":414,"tag":512,"props":3905,"children":3907},{"class":514,"line":3906},27,[3908],{"type":414,"tag":512,"props":3909,"children":3910},{"style":519},[3911],{"type":419,"value":3912},"# Create and use a folder to store the infrastructure code\n",{"type":414,"tag":512,"props":3914,"children":3916},{"class":514,"line":3915},28,[3917,3921,3925,3929],{"type":414,"tag":512,"props":3918,"children":3919},{"style":535},[3920],{"type":419,"value":2340},{"type":414,"tag":512,"props":3922,"children":3923},{"style":745},[3924],{"type":419,"value":2345},{"type":414,"tag":512,"props":3926,"children":3927},{"style":535},[3928],{"type":419,"value":2350},{"type":414,"tag":512,"props":3930,"children":3931},{"style":745},[3932],{"type":419,"value":2355},{"type":414,"tag":512,"props":3934,"children":3936},{"class":514,"line":3935},29,[3937],{"type":414,"tag":512,"props":3938,"children":3939},{"style":519},[3940],{"type":419,"value":3941},"# Create a new Pulumi project using the azure blob storage as the backend and the keyvault as the encryption provider \n",{"type":414,"tag":512,"props":3943,"children":3945},{"class":514,"line":3944},30,[3946,3950,3954,3958,3962,3966,3970,3974,3978,3982,3986,3990,3994,3998,4002,4006,4010,4014,4018,4022],{"type":414,"tag":512,"props":3947,"children":3948},{"style":535},[3949],{"type":419,"value":2363},{"type":414,"tag":512,"props":3951,"children":3952},{"style":745},[3953],{"type":419,"value":2137},{"type":414,"tag":512,"props":3955,"children":3956},{"style":535},[3957],{"type":419,"value":2372},{"type":414,"tag":512,"props":3959,"children":3960},{"style":745},[3961],{"type":419,"value":2137},{"type":414,"tag":512,"props":3963,"children":3964},{"style":535},[3965],{"type":419,"value":2381},{"type":414,"tag":512,"props":3967,"children":3968},{"style":745},[3969],{"type":419,"value":2137},{"type":414,"tag":512,"props":3971,"children":3972},{"style":535},[3973],{"type":419,"value":2390},{"type":414,"tag":512,"props":3975,"children":3976},{"style":745},[3977],{"type":419,"value":2137},{"type":414,"tag":512,"props":3979,"children":3980},{"style":535},[3981],{"type":419,"value":2994},{"type":414,"tag":512,"props":3983,"children":3984},{"style":745},[3985],{"type":419,"value":2183},{"type":414,"tag":512,"props":3987,"children":3988},{"style":535},[3989],{"type":419,"value":3003},{"type":414,"tag":512,"props":3991,"children":3992},{"style":745},[3993],{"type":419,"value":2137},{"type":414,"tag":512,"props":3995,"children":3996},{"style":535},[3997],{"type":419,"value":3012},{"type":414,"tag":512,"props":3999,"children":4000},{"style":745},[4001],{"type":419,"value":1781},{"type":414,"tag":512,"props":4003,"children":4004},{"style":745},[4005],{"type":419,"value":767},{"type":414,"tag":512,"props":4007,"children":4008},{"style":812},[4009],{"type":419,"value":3025},{"type":414,"tag":512,"props":4011,"children":4012},{"style":745},[4013],{"type":419,"value":1771},{"type":414,"tag":512,"props":4015,"children":4016},{"style":535},[4017],{"type":419,"value":2549},{"type":414,"tag":512,"props":4019,"children":4020},{"style":812},[4021],{"type":419,"value":3038},{"type":414,"tag":512,"props":4023,"children":4024},{"style":745},[4025],{"type":419,"value":897},{"type":414,"tag":512,"props":4027,"children":4029},{"class":514,"line":4028},31,[4030],{"type":414,"tag":512,"props":4031,"children":4032},{"style":519},[4033],{"type":419,"value":4034},"# Deploy the infrastructure\n",{"type":414,"tag":512,"props":4036,"children":4038},{"class":514,"line":4037},32,[4039,4043,4047],{"type":414,"tag":512,"props":4040,"children":4041},{"style":535},[4042],{"type":419,"value":2407},{"type":414,"tag":512,"props":4044,"children":4045},{"style":745},[4046],{"type":419,"value":2137},{"type":414,"tag":512,"props":4048,"children":4049},{"style":535},[4050],{"type":419,"value":2399},{"type":414,"tag":415,"props":4052,"children":4053},{},[4054],{"type":419,"value":4055},"Using Pulumi without Pulumi Service was not complicated as I thought it would be. I like the fact that Pulumi is not limited to being used with Pulumi Service backend and secret provider. It gives us the choice to use what we want: if I want to use Google Cloud Storage as my back-end and AWS Key Management Service as my encryption provider I totally can. Many options are available and well integrated without requiring much work which is nice.",{"type":414,"tag":415,"props":4057,"children":4058},{},[4059,4061,4068],{"type":419,"value":4060},"Yet honestly, I think that using Pulumi Service will be my default choice because of the many built-in features it offers (deployment history, concurrent state locking, collaboration functionalities, ...). It's free for individuals so I would not bother with a self-managed backend for individuals. For teams and companies, you have to pay (even if there is a monthly free grant of credits for the team plan) but I don't have enough perspective to say if it's worth it. You can find the pricing ",{"type":414,"tag":422,"props":4062,"children":4065},{"href":4063,"rel":4064},"https://www.pulumi.com/pricing/",[426],[4066],{"type":419,"value":4067},"here",{"type":419,"value":4069}," if you want to see it by yourself. I guess the choice between that and a self-managed backend will probably depend more on the project and the organization you are working for.",{"type":414,"tag":1469,"props":4071,"children":4072},{},[4073],{"type":419,"value":1473},{"title":401,"searchDepth":525,"depth":525,"links":4075},[4076,4080,4085,4090,4091],{"id":1501,"depth":525,"text":1504,"children":4077},[4078,4079],{"id":1508,"depth":775,"text":1511},{"id":1589,"depth":775,"text":1592},{"id":1633,"depth":525,"text":1636,"children":4081},[4082,4083,4084],{"id":1639,"depth":775,"text":1642},{"id":1701,"depth":775,"text":1704},{"id":2271,"depth":775,"text":2274},{"id":2452,"depth":525,"text":2455,"children":4086},[4087,4088,4089],{"id":2458,"depth":775,"text":2461},{"id":2474,"depth":775,"text":2477},{"id":2522,"depth":775,"text":2525},{"id":3045,"depth":525,"text":3048},{"id":3111,"depth":525,"text":3114},"content:1.posts:30.pulumi-azure-backend.md","1.posts/30.pulumi-azure-backend.md",{"_path":79,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":78,"description":4095,"lead":4096,"date":4097,"image":4098,"badge":4100,"tags":4102,"body":4103,"_type":1480,"_id":6131,"_source":1482,"_file":6132,"_extension":1484},"Have you ever felt a bit overwhelmed by the configuration in a project, not knowing where to look for the settings between the command line parameters, the environment variables, the configuration files in code, the configuration in Azure, ... ? When developing an ASP.NET Core application there are many places where you can put your configuration which makes it difficult to know where you should put it. Even if the official documentation about configuration in ASP.NET Core is very complete and well written, it only describes what you can use and how to use it, not what you should use and when. In this article,     I will try to answer these questions and give you my opinion about how we should use configuration providers in ASP.NET Core.","How should you use configuration providers in ASP.NET Core?","2021-09-27T00:00:00.000Z",{"src":4099},"/images/tokyo.jpg",{"label":4101},"Development",[236,262,260,228],{"type":411,"children":4104,"toc":6118},[4105,4119,4125,4130,4135,4144,4150,4155,4164,4177,4865,4893,4902,4907,4916,4943,4949,4954,4966,4992,5016,5022,5027,5036,5041,5047,5052,5069,5112,5121,5127,5132,5170,5179,5184,5189,5500,5505,5511,5525,5534,5539,5913,5919,5929,5943,5991,6000,6031,6037,6042,6047,6109,6114],{"type":414,"tag":415,"props":4106,"children":4107},{},[4108,4110,4117],{"type":419,"value":4109},"Have you ever felt a bit overwhelmed by the configuration in a project, not knowing where to look for the settings between the command line parameters, the environment variables, the configuration files in code, the configuration in Azure, ... ? When developing an ASP.NET Core application there are many places where you can put your configuration which makes it difficult to know where you should put it. Even if the ",{"type":414,"tag":422,"props":4111,"children":4114},{"href":4112,"rel":4113},"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/",[426],[4115],{"type":419,"value":4116},"official documentation",{"type":419,"value":4118}," about configuration in ASP.NET Core is very complete and well written, it only describes what you can use and how to use it, not what you should use and when. In this article,     I will try to answer these questions and give you my opinion about how we should use configuration providers in ASP.NET Core.",{"type":414,"tag":459,"props":4120,"children":4122},{"id":4121},"a-quick-reminder-about-configuration",[4123],{"type":419,"value":4124},"A quick reminder about configuration",{"type":414,"tag":415,"props":4126,"children":4127},{},[4128],{"type":419,"value":4129},"Configuration is what allows you to quickly change how an application behaves by modifying a setting instead of rewriting the code. Configuration/settings are sometimes linked to the environment where your application runs but not always. Generally, when something is likely to change, a good practice is to define a setting for it in the configuration instead of hard coding it in the source code.",{"type":414,"tag":415,"props":4131,"children":4132},{},[4133],{"type":419,"value":4134},"Configuration can take many forms and ASP.NET Core has this powerful concept of configurations providers that read configuration data from different sources. But in the end, configuration is just a collection of key-value pairs.",{"type":414,"tag":415,"props":4136,"children":4137},{},[4138],{"type":414,"tag":609,"props":4139,"children":4143},{"alt":4140,"className":4141,"src":4142},"Values in Startup.cs configuration in debug.",[613,614],"/posts/images/lostinconfiguration_providers_2.png",[],{"type":414,"tag":459,"props":4145,"children":4147},{"id":4146},"why-do-i-have-so-many-configuration-providers-by-default",[4148],{"type":419,"value":4149},"Why do I have so many configuration providers by default?",{"type":414,"tag":415,"props":4151,"children":4152},{},[4153],{"type":419,"value":4154},"When you create a new ASP.NET Core project from a template and run it, you have probably noticed that your configuration is not empty and that by default, multiple configuration providers are already registered.",{"type":414,"tag":415,"props":4156,"children":4157},{},[4158],{"type":414,"tag":609,"props":4159,"children":4163},{"alt":4160,"className":4161,"src":4162},"Configuration providers in Startup.cs configuration in debug.",[613,614],"/posts/images/lostinconfiguration_providers_1.pngpng",[],{"type":414,"tag":415,"props":4165,"children":4166},{},[4167,4169,4175],{"type":419,"value":4168},"Do not worry there is no magic here, it just comes from the call ",{"type":414,"tag":479,"props":4170,"children":4172},{"className":4171},[],[4173],{"type":419,"value":4174},"Host.CreateDefaultBuilder(args)",{"type":419,"value":4176}," in your Program.cs.\nHere is an extract of what does this method:",{"type":414,"tag":503,"props":4178,"children":4181},{"className":4179,"code":4180,"language":326,"meta":401,"style":401},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","builder.ConfigureAppConfiguration((hostingContext, config) =>\n{\n    IHostEnvironment env = hostingContext.HostingEnvironment;\n    bool reloadOnChange = GetReloadConfigOnChangeValue(hostingContext);\n    config.AddJsonFile(\"appsettings.json\", optional: true, reloadOnChange: reloadOnChange)\n          .AddJsonFile($\"appsettings.{env.EnvironmentName}.json\", optional: true, reloadOnChange:reloadOnChange);\n    if (env.IsDevelopment() && env.ApplicationName is { Length: > 0 })\n    {\n        var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));\n        if (appAssembly is not null)\n        {\n            config.AddUserSecrets(appAssembly, optional: true, reloadOnChange: reloadOnChange);\n        }\n    }\n    config.AddEnvironmentVariables();\n    if (args is { Length: > 0 })\n    {\n        config.AddCommandLine(args);\n    }\n})\n",[4182],{"type":414,"tag":479,"props":4183,"children":4184},{"__ignoreMap":401},[4185,4231,4238,4274,4310,4383,4478,4560,4568,4631,4662,4670,4732,4740,4748,4769,4813,4820,4850,4857],{"type":414,"tag":512,"props":4186,"children":4187},{"class":514,"line":515},[4188,4193,4197,4202,4207,4212,4217,4222,4226],{"type":414,"tag":512,"props":4189,"children":4190},{"style":535},[4191],{"type":419,"value":4192},"builder",{"type":414,"tag":512,"props":4194,"children":4195},{"style":745},[4196],{"type":419,"value":457},{"type":414,"tag":512,"props":4198,"children":4199},{"style":1784},[4200],{"type":419,"value":4201},"ConfigureAppConfiguration",{"type":414,"tag":512,"props":4203,"children":4204},{"style":745},[4205],{"type":419,"value":4206},"((",{"type":414,"tag":512,"props":4208,"children":4209},{"style":793},[4210],{"type":419,"value":4211},"hostingContext",{"type":414,"tag":512,"props":4213,"children":4214},{"style":745},[4215],{"type":419,"value":4216},",",{"type":414,"tag":512,"props":4218,"children":4219},{"style":793},[4220],{"type":419,"value":4221}," config",{"type":414,"tag":512,"props":4223,"children":4224},{"style":745},[4225],{"type":419,"value":1333},{"type":414,"tag":512,"props":4227,"children":4228},{"style":745},[4229],{"type":419,"value":4230}," =>\n",{"type":414,"tag":512,"props":4232,"children":4233},{"class":514,"line":525},[4234],{"type":414,"tag":512,"props":4235,"children":4236},{"style":745},[4237],{"type":419,"value":748},{"type":414,"tag":512,"props":4239,"children":4240},{"class":514,"line":775},[4241,4246,4251,4256,4261,4265,4270],{"type":414,"tag":512,"props":4242,"children":4243},{"style":793},[4244],{"type":419,"value":4245},"    IHostEnvironment",{"type":414,"tag":512,"props":4247,"children":4248},{"style":793},[4249],{"type":419,"value":4250}," env",{"type":414,"tag":512,"props":4252,"children":4253},{"style":745},[4254],{"type":419,"value":4255}," =",{"type":414,"tag":512,"props":4257,"children":4258},{"style":535},[4259],{"type":419,"value":4260}," hostingContext",{"type":414,"tag":512,"props":4262,"children":4263},{"style":745},[4264],{"type":419,"value":457},{"type":414,"tag":512,"props":4266,"children":4267},{"style":535},[4268],{"type":419,"value":4269},"HostingEnvironment",{"type":414,"tag":512,"props":4271,"children":4272},{"style":745},[4273],{"type":419,"value":2355},{"type":414,"tag":512,"props":4275,"children":4276},{"class":514,"line":784},[4277,4282,4287,4291,4296,4301,4305],{"type":414,"tag":512,"props":4278,"children":4279},{"style":745},[4280],{"type":419,"value":4281},"    bool",{"type":414,"tag":512,"props":4283,"children":4284},{"style":793},[4285],{"type":419,"value":4286}," reloadOnChange",{"type":414,"tag":512,"props":4288,"children":4289},{"style":745},[4290],{"type":419,"value":4255},{"type":414,"tag":512,"props":4292,"children":4293},{"style":1784},[4294],{"type":419,"value":4295}," GetReloadConfigOnChangeValue",{"type":414,"tag":512,"props":4297,"children":4298},{"style":745},[4299],{"type":419,"value":4300},"(",{"type":414,"tag":512,"props":4302,"children":4303},{"style":535},[4304],{"type":419,"value":4211},{"type":414,"tag":512,"props":4306,"children":4307},{"style":745},[4308],{"type":419,"value":4309},");\n",{"type":414,"tag":512,"props":4311,"children":4312},{"class":514,"line":827},[4313,4318,4322,4327,4331,4335,4340,4344,4348,4353,4357,4363,4367,4371,4375,4379],{"type":414,"tag":512,"props":4314,"children":4315},{"style":535},[4316],{"type":419,"value":4317},"    config",{"type":414,"tag":512,"props":4319,"children":4320},{"style":745},[4321],{"type":419,"value":457},{"type":414,"tag":512,"props":4323,"children":4324},{"style":1784},[4325],{"type":419,"value":4326},"AddJsonFile",{"type":414,"tag":512,"props":4328,"children":4329},{"style":745},[4330],{"type":419,"value":4300},{"type":414,"tag":512,"props":4332,"children":4333},{"style":745},[4334],{"type":419,"value":767},{"type":414,"tag":512,"props":4336,"children":4337},{"style":812},[4338],{"type":419,"value":4339},"appsettings.json",{"type":414,"tag":512,"props":4341,"children":4342},{"style":745},[4343],{"type":419,"value":767},{"type":414,"tag":512,"props":4345,"children":4346},{"style":745},[4347],{"type":419,"value":4216},{"type":414,"tag":512,"props":4349,"children":4350},{"style":793},[4351],{"type":419,"value":4352}," optional",{"type":414,"tag":512,"props":4354,"children":4355},{"style":745},[4356],{"type":419,"value":730},{"type":414,"tag":512,"props":4358,"children":4360},{"style":4359},"--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC",[4361],{"type":419,"value":4362}," true",{"type":414,"tag":512,"props":4364,"children":4365},{"style":745},[4366],{"type":419,"value":4216},{"type":414,"tag":512,"props":4368,"children":4369},{"style":793},[4370],{"type":419,"value":4286},{"type":414,"tag":512,"props":4372,"children":4373},{"style":745},[4374],{"type":419,"value":730},{"type":414,"tag":512,"props":4376,"children":4377},{"style":535},[4378],{"type":419,"value":4286},{"type":414,"tag":512,"props":4380,"children":4381},{"style":745},[4382],{"type":419,"value":1437},{"type":414,"tag":512,"props":4384,"children":4385},{"class":514,"line":865},[4386,4391,4395,4399,4404,4409,4414,4419,4423,4428,4432,4437,4441,4445,4449,4453,4457,4461,4465,4469,4474],{"type":414,"tag":512,"props":4387,"children":4388},{"style":745},[4389],{"type":419,"value":4390},"          .",{"type":414,"tag":512,"props":4392,"children":4393},{"style":1784},[4394],{"type":419,"value":4326},{"type":414,"tag":512,"props":4396,"children":4397},{"style":745},[4398],{"type":419,"value":4300},{"type":414,"tag":512,"props":4400,"children":4401},{"style":745},[4402],{"type":419,"value":4403},"$\"",{"type":414,"tag":512,"props":4405,"children":4406},{"style":812},[4407],{"type":419,"value":4408},"appsettings.",{"type":414,"tag":512,"props":4410,"children":4411},{"style":745},[4412],{"type":419,"value":4413},"{",{"type":414,"tag":512,"props":4415,"children":4416},{"style":535},[4417],{"type":419,"value":4418},"env",{"type":414,"tag":512,"props":4420,"children":4421},{"style":745},[4422],{"type":419,"value":457},{"type":414,"tag":512,"props":4424,"children":4425},{"style":535},[4426],{"type":419,"value":4427},"EnvironmentName",{"type":414,"tag":512,"props":4429,"children":4430},{"style":745},[4431],{"type":419,"value":1338},{"type":414,"tag":512,"props":4433,"children":4434},{"style":812},[4435],{"type":419,"value":4436},".json",{"type":414,"tag":512,"props":4438,"children":4439},{"style":745},[4440],{"type":419,"value":767},{"type":414,"tag":512,"props":4442,"children":4443},{"style":745},[4444],{"type":419,"value":4216},{"type":414,"tag":512,"props":4446,"children":4447},{"style":793},[4448],{"type":419,"value":4352},{"type":414,"tag":512,"props":4450,"children":4451},{"style":745},[4452],{"type":419,"value":730},{"type":414,"tag":512,"props":4454,"children":4455},{"style":4359},[4456],{"type":419,"value":4362},{"type":414,"tag":512,"props":4458,"children":4459},{"style":745},[4460],{"type":419,"value":4216},{"type":414,"tag":512,"props":4462,"children":4463},{"style":793},[4464],{"type":419,"value":4286},{"type":414,"tag":512,"props":4466,"children":4467},{"style":745},[4468],{"type":419,"value":730},{"type":414,"tag":512,"props":4470,"children":4471},{"style":535},[4472],{"type":419,"value":4473},"reloadOnChange",{"type":414,"tag":512,"props":4475,"children":4476},{"style":745},[4477],{"type":419,"value":4309},{"type":414,"tag":512,"props":4479,"children":4480},{"class":514,"line":900},[4481,4486,4491,4495,4499,4504,4509,4514,4518,4522,4527,4532,4536,4541,4545,4550,4555],{"type":414,"tag":512,"props":4482,"children":4483},{"style":529},[4484],{"type":419,"value":4485},"    if",{"type":414,"tag":512,"props":4487,"children":4488},{"style":745},[4489],{"type":419,"value":4490}," (",{"type":414,"tag":512,"props":4492,"children":4493},{"style":535},[4494],{"type":419,"value":4418},{"type":414,"tag":512,"props":4496,"children":4497},{"style":745},[4498],{"type":419,"value":457},{"type":414,"tag":512,"props":4500,"children":4501},{"style":1784},[4502],{"type":419,"value":4503},"IsDevelopment",{"type":414,"tag":512,"props":4505,"children":4506},{"style":745},[4507],{"type":419,"value":4508},"()",{"type":414,"tag":512,"props":4510,"children":4511},{"style":745},[4512],{"type":419,"value":4513}," &&",{"type":414,"tag":512,"props":4515,"children":4516},{"style":535},[4517],{"type":419,"value":4250},{"type":414,"tag":512,"props":4519,"children":4520},{"style":745},[4521],{"type":419,"value":457},{"type":414,"tag":512,"props":4523,"children":4524},{"style":535},[4525],{"type":419,"value":4526},"ApplicationName ",{"type":414,"tag":512,"props":4528,"children":4529},{"style":745},[4530],{"type":419,"value":4531},"is",{"type":414,"tag":512,"props":4533,"children":4534},{"style":745},[4535],{"type":419,"value":1259},{"type":414,"tag":512,"props":4537,"children":4538},{"style":535},[4539],{"type":419,"value":4540}," Length",{"type":414,"tag":512,"props":4542,"children":4543},{"style":745},[4544],{"type":419,"value":730},{"type":414,"tag":512,"props":4546,"children":4547},{"style":745},[4548],{"type":419,"value":4549}," >",{"type":414,"tag":512,"props":4551,"children":4552},{"style":541},[4553],{"type":419,"value":4554}," 0",{"type":414,"tag":512,"props":4556,"children":4557},{"style":745},[4558],{"type":419,"value":4559}," })\n",{"type":414,"tag":512,"props":4561,"children":4562},{"class":514,"line":909},[4563],{"type":414,"tag":512,"props":4564,"children":4565},{"style":745},[4566],{"type":419,"value":4567},"    {\n",{"type":414,"tag":512,"props":4569,"children":4570},{"class":514,"line":1431},[4571,4576,4581,4585,4590,4594,4599,4604,4609,4613,4617,4621,4626],{"type":414,"tag":512,"props":4572,"children":4573},{"style":793},[4574],{"type":419,"value":4575},"        var",{"type":414,"tag":512,"props":4577,"children":4578},{"style":793},[4579],{"type":419,"value":4580}," appAssembly",{"type":414,"tag":512,"props":4582,"children":4583},{"style":745},[4584],{"type":419,"value":4255},{"type":414,"tag":512,"props":4586,"children":4587},{"style":535},[4588],{"type":419,"value":4589}," Assembly",{"type":414,"tag":512,"props":4591,"children":4592},{"style":745},[4593],{"type":419,"value":457},{"type":414,"tag":512,"props":4595,"children":4596},{"style":1784},[4597],{"type":419,"value":4598},"Load",{"type":414,"tag":512,"props":4600,"children":4601},{"style":745},[4602],{"type":419,"value":4603},"(new",{"type":414,"tag":512,"props":4605,"children":4606},{"style":793},[4607],{"type":419,"value":4608}," AssemblyName",{"type":414,"tag":512,"props":4610,"children":4611},{"style":745},[4612],{"type":419,"value":4300},{"type":414,"tag":512,"props":4614,"children":4615},{"style":535},[4616],{"type":419,"value":4418},{"type":414,"tag":512,"props":4618,"children":4619},{"style":745},[4620],{"type":419,"value":457},{"type":414,"tag":512,"props":4622,"children":4623},{"style":535},[4624],{"type":419,"value":4625},"ApplicationName",{"type":414,"tag":512,"props":4627,"children":4628},{"style":745},[4629],{"type":419,"value":4630},"));\n",{"type":414,"tag":512,"props":4632,"children":4633},{"class":514,"line":3358},[4634,4639,4643,4648,4652,4657],{"type":414,"tag":512,"props":4635,"children":4636},{"style":529},[4637],{"type":419,"value":4638},"        if",{"type":414,"tag":512,"props":4640,"children":4641},{"style":745},[4642],{"type":419,"value":4490},{"type":414,"tag":512,"props":4644,"children":4645},{"style":535},[4646],{"type":419,"value":4647},"appAssembly ",{"type":414,"tag":512,"props":4649,"children":4650},{"style":745},[4651],{"type":419,"value":4531},{"type":414,"tag":512,"props":4653,"children":4654},{"style":745},[4655],{"type":419,"value":4656}," not",{"type":414,"tag":512,"props":4658,"children":4659},{"style":745},[4660],{"type":419,"value":4661}," null)\n",{"type":414,"tag":512,"props":4663,"children":4664},{"class":514,"line":3367},[4665],{"type":414,"tag":512,"props":4666,"children":4667},{"style":745},[4668],{"type":419,"value":4669},"        {\n",{"type":414,"tag":512,"props":4671,"children":4672},{"class":514,"line":3434},[4673,4678,4682,4687,4691,4696,4700,4704,4708,4712,4716,4720,4724,4728],{"type":414,"tag":512,"props":4674,"children":4675},{"style":535},[4676],{"type":419,"value":4677},"            config",{"type":414,"tag":512,"props":4679,"children":4680},{"style":745},[4681],{"type":419,"value":457},{"type":414,"tag":512,"props":4683,"children":4684},{"style":1784},[4685],{"type":419,"value":4686},"AddUserSecrets",{"type":414,"tag":512,"props":4688,"children":4689},{"style":745},[4690],{"type":419,"value":4300},{"type":414,"tag":512,"props":4692,"children":4693},{"style":535},[4694],{"type":419,"value":4695},"appAssembly",{"type":414,"tag":512,"props":4697,"children":4698},{"style":745},[4699],{"type":419,"value":4216},{"type":414,"tag":512,"props":4701,"children":4702},{"style":793},[4703],{"type":419,"value":4352},{"type":414,"tag":512,"props":4705,"children":4706},{"style":745},[4707],{"type":419,"value":730},{"type":414,"tag":512,"props":4709,"children":4710},{"style":4359},[4711],{"type":419,"value":4362},{"type":414,"tag":512,"props":4713,"children":4714},{"style":745},[4715],{"type":419,"value":4216},{"type":414,"tag":512,"props":4717,"children":4718},{"style":793},[4719],{"type":419,"value":4286},{"type":414,"tag":512,"props":4721,"children":4722},{"style":745},[4723],{"type":419,"value":730},{"type":414,"tag":512,"props":4725,"children":4726},{"style":535},[4727],{"type":419,"value":4286},{"type":414,"tag":512,"props":4729,"children":4730},{"style":745},[4731],{"type":419,"value":4309},{"type":414,"tag":512,"props":4733,"children":4734},{"class":514,"line":3443},[4735],{"type":414,"tag":512,"props":4736,"children":4737},{"style":745},[4738],{"type":419,"value":4739},"        }\n",{"type":414,"tag":512,"props":4741,"children":4742},{"class":514,"line":3527},[4743],{"type":414,"tag":512,"props":4744,"children":4745},{"style":745},[4746],{"type":419,"value":4747},"    }\n",{"type":414,"tag":512,"props":4749,"children":4750},{"class":514,"line":3547},[4751,4755,4759,4764],{"type":414,"tag":512,"props":4752,"children":4753},{"style":535},[4754],{"type":419,"value":4317},{"type":414,"tag":512,"props":4756,"children":4757},{"style":745},[4758],{"type":419,"value":457},{"type":414,"tag":512,"props":4760,"children":4761},{"style":1784},[4762],{"type":419,"value":4763},"AddEnvironmentVariables",{"type":414,"tag":512,"props":4765,"children":4766},{"style":745},[4767],{"type":419,"value":4768},"();\n",{"type":414,"tag":512,"props":4770,"children":4771},{"class":514,"line":3565},[4772,4776,4780,4785,4789,4793,4797,4801,4805,4809],{"type":414,"tag":512,"props":4773,"children":4774},{"style":529},[4775],{"type":419,"value":4485},{"type":414,"tag":512,"props":4777,"children":4778},{"style":745},[4779],{"type":419,"value":4490},{"type":414,"tag":512,"props":4781,"children":4782},{"style":535},[4783],{"type":419,"value":4784},"args ",{"type":414,"tag":512,"props":4786,"children":4787},{"style":745},[4788],{"type":419,"value":4531},{"type":414,"tag":512,"props":4790,"children":4791},{"style":745},[4792],{"type":419,"value":1259},{"type":414,"tag":512,"props":4794,"children":4795},{"style":535},[4796],{"type":419,"value":4540},{"type":414,"tag":512,"props":4798,"children":4799},{"style":745},[4800],{"type":419,"value":730},{"type":414,"tag":512,"props":4802,"children":4803},{"style":745},[4804],{"type":419,"value":4549},{"type":414,"tag":512,"props":4806,"children":4807},{"style":541},[4808],{"type":419,"value":4554},{"type":414,"tag":512,"props":4810,"children":4811},{"style":745},[4812],{"type":419,"value":4559},{"type":414,"tag":512,"props":4814,"children":4815},{"class":514,"line":3573},[4816],{"type":414,"tag":512,"props":4817,"children":4818},{"style":745},[4819],{"type":419,"value":4567},{"type":414,"tag":512,"props":4821,"children":4822},{"class":514,"line":3582},[4823,4828,4832,4837,4841,4846],{"type":414,"tag":512,"props":4824,"children":4825},{"style":535},[4826],{"type":419,"value":4827},"        config",{"type":414,"tag":512,"props":4829,"children":4830},{"style":745},[4831],{"type":419,"value":457},{"type":414,"tag":512,"props":4833,"children":4834},{"style":1784},[4835],{"type":419,"value":4836},"AddCommandLine",{"type":414,"tag":512,"props":4838,"children":4839},{"style":745},[4840],{"type":419,"value":4300},{"type":414,"tag":512,"props":4842,"children":4843},{"style":535},[4844],{"type":419,"value":4845},"args",{"type":414,"tag":512,"props":4847,"children":4848},{"style":745},[4849],{"type":419,"value":4309},{"type":414,"tag":512,"props":4851,"children":4852},{"class":514,"line":3670},[4853],{"type":414,"tag":512,"props":4854,"children":4855},{"style":745},[4856],{"type":419,"value":4747},{"type":414,"tag":512,"props":4858,"children":4859},{"class":514,"line":3735},[4860],{"type":414,"tag":512,"props":4861,"children":4862},{"style":745},[4863],{"type":419,"value":4864},"})\n",{"type":414,"tag":415,"props":4866,"children":4867},{},[4868,4870,4876,4878,4883,4885,4891],{"type":419,"value":4869},"As you can see, by default this ",{"type":414,"tag":479,"props":4871,"children":4873},{"className":4872},[],[4874],{"type":419,"value":4875},"CreateDefaultBuilder",{"type":419,"value":4877}," method loads configuration data using different configuration providers. You can load additional configuration by calling the ",{"type":414,"tag":479,"props":4879,"children":4881},{"className":4880},[],[4882],{"type":419,"value":4201},{"type":419,"value":4884}," in the ",{"type":414,"tag":479,"props":4886,"children":4888},{"className":4887},[],[4889],{"type":419,"value":4890},"Program.cs",{"type":419,"value":4892}," like in the example which uses Azure Key Vault configuration provider.",{"type":414,"tag":415,"props":4894,"children":4895},{},[4896],{"type":414,"tag":609,"props":4897,"children":4901},{"alt":4898,"className":4899,"src":4900},"Code for using ConfigureAppConfiguration in Program.cs.",[613,614],"/posts/images/lostinconfiguration_providers_4.png",[],{"type":414,"tag":415,"props":4903,"children":4904},{},[4905],{"type":419,"value":4906},"It is important to know that order in which the configuration provider is specified matters: in case multiple providers load different values for the same setting, the value of the last provider specifying this setting is the one that will be used in the configuration. You can see in which order the configuration is loaded from different sources in the method documentation.",{"type":414,"tag":415,"props":4908,"children":4909},{},[4910],{"type":414,"tag":609,"props":4911,"children":4915},{"alt":4912,"className":4913,"src":4914},"CreateDefaultBuilder documentation in IDE.",[613,614],"/posts/images/lostinconfiguration_providers_3.png",[],{"type":414,"tag":415,"props":4917,"children":4918},{},[4919,4921,4927,4929,4934,4936,4941],{"type":419,"value":4920},"If the order in which configuration providers are registered by default does not suit you, then you can simply create the ",{"type":414,"tag":479,"props":4922,"children":4924},{"className":4923},[],[4925],{"type":419,"value":4926},"HostBuilder",{"type":419,"value":4928}," yourself in ",{"type":414,"tag":479,"props":4930,"children":4932},{"className":4931},[],[4933],{"type":419,"value":4890},{"type":419,"value":4935}," instead of using ",{"type":414,"tag":479,"props":4937,"children":4939},{"className":4938},[],[4940],{"type":419,"value":4875},{"type":419,"value":4942}," method.",{"type":414,"tag":459,"props":4944,"children":4946},{"id":4945},"how-to-have-a-global-view-of-the-configuration-used-by-your-application",[4947],{"type":419,"value":4948},"How to have a global view of the configuration used by your application?",{"type":414,"tag":415,"props":4950,"children":4951},{},[4952],{"type":419,"value":4953},"Having different providers to load the configuration in your application is great but one drawback is that the configuration is scattered all over the place. Indeed sometimes we want to have the complete list of settings an application uses and if we have to look everywhere (key vault, environment variables, JSON files,...) it becomes impossible to manage.",{"type":414,"tag":415,"props":4955,"children":4956},{},[4957,4959,4964],{"type":419,"value":4958},"What I advise is to put all the settings you use in your application in the ",{"type":414,"tag":479,"props":4960,"children":4962},{"className":4961},[],[4963],{"type":419,"value":4339},{"type":419,"value":4965}," file. It does not mean you will put all the values there too or that the values you put there will be the ones that your application will use. But it means that you will have one place where you can quickly look what are the different settings keys. And concerning the values of these settings, if they should come from another file or provider (because they are relative to an environment or because they are secrets for instance), that is not a problem just put a blank value.",{"type":414,"tag":415,"props":4967,"children":4968},{},[4969,4971,4976,4978,4983,4985,4990],{"type":419,"value":4970},"So why using the ",{"type":414,"tag":479,"props":4972,"children":4974},{"className":4973},[],[4975],{"type":419,"value":4339},{"type":419,"value":4977}," file for that? In the last section, I showed the code that loads some configuration by default and you may have noticed that this settings file is the first loaded into configuration. That means any following configuration source will override the existing values coming from the ",{"type":414,"tag":479,"props":4979,"children":4981},{"className":4980},[],[4982],{"type":419,"value":4339},{"type":419,"value":4984}," file, so having all the settings declared in the ",{"type":414,"tag":479,"props":4986,"children":4988},{"className":4987},[],[4989],{"type":419,"value":4339},{"type":419,"value":4991}," file won't be a problem even if some have blank values (they will be overridden by the values loaded after).",{"type":414,"tag":623,"props":4993,"children":4994},{"icon":625},[4995],{"type":414,"tag":415,"props":4996,"children":4997},{},[4998,5000,5007,5009,5015],{"type":419,"value":4999},"When running your application locally, if you want to display what are the values of the settings in your configuration and where their values come from you can read ",{"type":414,"tag":422,"props":5001,"children":5004},{"href":5002,"rel":5003},"https://andrewlock.net/debugging-configuration-values-in-aspnetcore/",[426],[5005],{"type":419,"value":5006},"this article",{"type":419,"value":5008}," by Andrew Lock that explains how to do that using the ",{"type":414,"tag":479,"props":5010,"children":5012},{"className":5011},[],[5013],{"type":419,"value":5014},"IConfigurationRoot.GetDebugView()",{"type":419,"value":4942},{"type":414,"tag":459,"props":5017,"children":5019},{"id":5018},"what-about-configuration-in-an-app-service-or-an-azure-function-is-it-a-specific-configuration-provider",[5020],{"type":419,"value":5021},"What about configuration in an App Service or an Azure Function, is it a specific configuration provider?",{"type":414,"tag":415,"props":5023,"children":5024},{},[5025],{"type":419,"value":5026},"Well, the answer is no. Application settings in the configuration of an App Service or a Function App (the settings you can see in the Azure portal) are passed as environment variables to the application.",{"type":414,"tag":415,"props":5028,"children":5029},{},[5030],{"type":414,"tag":609,"props":5031,"children":5035},{"alt":5032,"className":5033,"src":5034},"Application settings in the configuration of an App Service.",[613,614],"/posts/images/lostinconfiguration_azureconfig_1.png",[],{"type":414,"tag":415,"props":5037,"children":5038},{},[5039],{"type":419,"value":5040},"If you remember in which order the providers are registered, it means that configuration in Azure will override most of the configuration coming from other providers.",{"type":414,"tag":459,"props":5042,"children":5044},{"id":5043},"where-to-put-environment-dependent-configuration",[5045],{"type":419,"value":5046},"Where to put environment-dependent configuration?",{"type":414,"tag":415,"props":5048,"children":5049},{},[5050],{"type":419,"value":5051},"As the name suggests, environment variables are a good place to set your environment-dependent configuration. If you are deploying your ASP.NET Core application in an Azure App Service, you can set these environment variables in the application settings section of your App Service in the Azure portal. However, I guess you are probably using an Infrastructure as Code tool (like Pulumi or Terraform) instead of manually modifying your Azure resources in the portal, so that means your environment-dependent configuration will be stored among your infrastructure code and deployed to Azure with the rest of the infrastructure.",{"type":414,"tag":623,"props":5053,"children":5054},{"icon":625},[5055],{"type":414,"tag":415,"props":5056,"children":5057},{},[5058,5060,5067],{"type":419,"value":5059},"To know more about how are managed Environments in ASP.NET Core you can read ",{"type":414,"tag":422,"props":5061,"children":5064},{"href":5062,"rel":5063},"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments",[426],[5065],{"type":419,"value":5066},"this page of the official documentation",{"type":419,"value":5068}," that talks about that.",{"type":414,"tag":415,"props":5070,"children":5071},{},[5072,5074,5079,5081,5087,5089,5095,5097,5103,5105,5110],{"type":419,"value":5073},"Using environment variables is a good approach but it is less convenient than having settings in your JSON settings files. Moreover, if these environment settings are only in your cloud resources, you will miss some settings when you debug your application locally. That's why I think it is a good idea to take advantage of ASP.NET Core default behavior  (see ",{"type":414,"tag":479,"props":5075,"children":5077},{"className":5076},[],[5078],{"type":419,"value":4875},{"type":419,"value":5080}," implementation above) of loading the ",{"type":414,"tag":479,"props":5082,"children":5084},{"className":5083},[],[5085],{"type":419,"value":5086},"appsettings",{"type":419,"value":5088}," JSON file corresponding to the current environment. That way, if you have for example a staging environment you can set the environment variable ",{"type":414,"tag":479,"props":5090,"children":5092},{"className":5091},[],[5093],{"type":419,"value":5094},"ASPNETCORE_ENVIRONMENT",{"type":419,"value":5096}," to staging and put all your configuration for staging in the ",{"type":414,"tag":479,"props":5098,"children":5100},{"className":5099},[],[5101],{"type":419,"value":5102},"appsettings.staging.json",{"type":419,"value":5104},". This may not work for everything as some settings depend on your infrastructure deployment (maybe you only know the value of a setting after the deployment of the infrastructure), but in that case you will put these settings in your environment variables thanks to your infrastructure code and anyway that should not prevent you from putting them in your ",{"type":414,"tag":479,"props":5106,"children":5108},{"className":5107},[],[5109],{"type":419,"value":4339},{"type":419,"value":5111}," files afterward to make local debug easier.",{"type":414,"tag":415,"props":5113,"children":5114},{},[5115],{"type":414,"tag":609,"props":5116,"children":5120},{"alt":5117,"className":5118,"src":5119},"App settings files in files explorer of an IDE.",[613,614],"/posts/images/lostinconfiguration_appsettings_1.png",[],{"type":414,"tag":459,"props":5122,"children":5124},{"id":5123},"how-to-deal-with-secrets-in-my-application-configuration",[5125],{"type":419,"value":5126},"How to deal with secrets in my application configuration?",{"type":414,"tag":415,"props":5128,"children":5129},{},[5130],{"type":419,"value":5131},"There are multiple ways of handling secrets but there is one fundamental rule: 'never commit a secret in source control'. Whatever the context, there is no valid reason that justifies putting a value in source code, that's it.",{"type":414,"tag":415,"props":5133,"children":5134},{},[5135,5137,5144,5146,5152,5154,5161,5163,5168],{"type":419,"value":5136},"One easy way to avoid having secrets in your source code is to use ",{"type":414,"tag":422,"props":5138,"children":5141},{"href":5139,"rel":5140},"https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets#secret-manager",[426],[5142],{"type":419,"value":5143},"Secret Manager",{"type":419,"value":5145},". It is a nice tool that allows you to put your secrets in a ",{"type":414,"tag":479,"props":5147,"children":5149},{"className":5148},[],[5150],{"type":419,"value":5151},"secrets.json",{"type":419,"value":5153}," file stored in your user profile directory (thus not committed with the rest of the code). When your application runs locally, secrets are loaded from this file in your application configuration thanks to the ",{"type":414,"tag":422,"props":5155,"children":5158},{"href":5156,"rel":5157},"https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0#file-configuration-provider",[426],[5159],{"type":419,"value":5160},"File configuration provider",{"type":419,"value":5162}," and everything works fine without having to put secrets in the configuration files in source control (",{"type":414,"tag":479,"props":5164,"children":5166},{"className":5165},[],[5167],{"type":419,"value":4339},{"type":419,"value":5169}," for instance).",{"type":414,"tag":415,"props":5171,"children":5172},{},[5173],{"type":414,"tag":609,"props":5174,"children":5178},{"alt":5175,"className":5176,"src":5177},"Secrets.json file and option to generate it in Visual Studio.",[613,614],"/posts/images/lostinconfiguration_secrets_1.png",[],{"type":414,"tag":415,"props":5180,"children":5181},{},[5182],{"type":419,"value":5183},"Secret manager is interesting to debug your application locally when developing but apart from that you will want to use a vault to safely store your secrets and make them available to your application. Each cloud provider has its vault solution: Azure Key Vault, AWS Secret Manager, Google Cloud Secret Manager, and there are also third-party vaults like HashiCorp Vault for instance. To integrate with a vault, you could write your own custom provider that loads the secrets from the vault into configuration but for each of these vaults, there is a configuration provider package supported by the editor or the community.",{"type":414,"tag":415,"props":5185,"children":5186},{},[5187],{"type":419,"value":5188},"For instance, to inject secrets from an Azure KeyVault in your configuration you should use the following code:",{"type":414,"tag":503,"props":5190,"children":5192},{"className":4179,"code":5191,"language":326,"meta":401,"style":401},"public static IHostBuilder CreateHostBuilder(string[] args) =>\n    Host.CreateDefaultBuilder()\n        .ConfigureAppConfiguration((context, config) =>\n        {\n            var keyVaultEndpoint = new Uri(Environment.GetEnvironmentVariable(\"VaultUri\"));\n            config.AddAzureKeyVault(keyVaultEndpoint, new DefaultAzureCredential());\n        })\n        .ConfigureWebHostDefaults(webBuilder =>\n        {\n            webBuilder.UseStartup\u003CStartup>();\n        });\n",[5193],{"type":414,"tag":479,"props":5194,"children":5195},{"__ignoreMap":401},[5196,5246,5267,5304,5311,5377,5420,5428,5453,5460,5492],{"type":414,"tag":512,"props":5197,"children":5198},{"class":514,"line":515},[5199,5204,5209,5214,5219,5223,5228,5233,5238,5242],{"type":414,"tag":512,"props":5200,"children":5201},{"style":759},[5202],{"type":419,"value":5203},"public",{"type":414,"tag":512,"props":5205,"children":5206},{"style":759},[5207],{"type":419,"value":5208}," static",{"type":414,"tag":512,"props":5210,"children":5211},{"style":793},[5212],{"type":419,"value":5213}," IHostBuilder",{"type":414,"tag":512,"props":5215,"children":5216},{"style":1784},[5217],{"type":419,"value":5218}," CreateHostBuilder",{"type":414,"tag":512,"props":5220,"children":5221},{"style":745},[5222],{"type":419,"value":4300},{"type":414,"tag":512,"props":5224,"children":5225},{"style":745},[5226],{"type":419,"value":5227},"string",{"type":414,"tag":512,"props":5229,"children":5230},{"style":745},[5231],{"type":419,"value":5232},"[]",{"type":414,"tag":512,"props":5234,"children":5235},{"style":793},[5236],{"type":419,"value":5237}," args",{"type":414,"tag":512,"props":5239,"children":5240},{"style":745},[5241],{"type":419,"value":1333},{"type":414,"tag":512,"props":5243,"children":5244},{"style":745},[5245],{"type":419,"value":4230},{"type":414,"tag":512,"props":5247,"children":5248},{"class":514,"line":525},[5249,5254,5258,5262],{"type":414,"tag":512,"props":5250,"children":5251},{"style":535},[5252],{"type":419,"value":5253},"    Host",{"type":414,"tag":512,"props":5255,"children":5256},{"style":745},[5257],{"type":419,"value":457},{"type":414,"tag":512,"props":5259,"children":5260},{"style":1784},[5261],{"type":419,"value":4875},{"type":414,"tag":512,"props":5263,"children":5264},{"style":745},[5265],{"type":419,"value":5266},"()\n",{"type":414,"tag":512,"props":5268,"children":5269},{"class":514,"line":775},[5270,5275,5279,5283,5288,5292,5296,5300],{"type":414,"tag":512,"props":5271,"children":5272},{"style":745},[5273],{"type":419,"value":5274},"        .",{"type":414,"tag":512,"props":5276,"children":5277},{"style":1784},[5278],{"type":419,"value":4201},{"type":414,"tag":512,"props":5280,"children":5281},{"style":745},[5282],{"type":419,"value":4206},{"type":414,"tag":512,"props":5284,"children":5285},{"style":793},[5286],{"type":419,"value":5287},"context",{"type":414,"tag":512,"props":5289,"children":5290},{"style":745},[5291],{"type":419,"value":4216},{"type":414,"tag":512,"props":5293,"children":5294},{"style":793},[5295],{"type":419,"value":4221},{"type":414,"tag":512,"props":5297,"children":5298},{"style":745},[5299],{"type":419,"value":1333},{"type":414,"tag":512,"props":5301,"children":5302},{"style":745},[5303],{"type":419,"value":4230},{"type":414,"tag":512,"props":5305,"children":5306},{"class":514,"line":784},[5307],{"type":414,"tag":512,"props":5308,"children":5309},{"style":745},[5310],{"type":419,"value":4669},{"type":414,"tag":512,"props":5312,"children":5313},{"class":514,"line":827},[5314,5319,5324,5328,5333,5338,5342,5347,5351,5356,5360,5364,5369,5373],{"type":414,"tag":512,"props":5315,"children":5316},{"style":793},[5317],{"type":419,"value":5318},"            var",{"type":414,"tag":512,"props":5320,"children":5321},{"style":793},[5322],{"type":419,"value":5323}," keyVaultEndpoint",{"type":414,"tag":512,"props":5325,"children":5326},{"style":745},[5327],{"type":419,"value":4255},{"type":414,"tag":512,"props":5329,"children":5330},{"style":745},[5331],{"type":419,"value":5332}," new",{"type":414,"tag":512,"props":5334,"children":5335},{"style":793},[5336],{"type":419,"value":5337}," Uri",{"type":414,"tag":512,"props":5339,"children":5340},{"style":745},[5341],{"type":419,"value":4300},{"type":414,"tag":512,"props":5343,"children":5344},{"style":535},[5345],{"type":419,"value":5346},"Environment",{"type":414,"tag":512,"props":5348,"children":5349},{"style":745},[5350],{"type":419,"value":457},{"type":414,"tag":512,"props":5352,"children":5353},{"style":1784},[5354],{"type":419,"value":5355},"GetEnvironmentVariable",{"type":414,"tag":512,"props":5357,"children":5358},{"style":745},[5359],{"type":419,"value":4300},{"type":414,"tag":512,"props":5361,"children":5362},{"style":745},[5363],{"type":419,"value":767},{"type":414,"tag":512,"props":5365,"children":5366},{"style":812},[5367],{"type":419,"value":5368},"VaultUri",{"type":414,"tag":512,"props":5370,"children":5371},{"style":745},[5372],{"type":419,"value":767},{"type":414,"tag":512,"props":5374,"children":5375},{"style":745},[5376],{"type":419,"value":4630},{"type":414,"tag":512,"props":5378,"children":5379},{"class":514,"line":865},[5380,5384,5388,5393,5397,5402,5406,5410,5415],{"type":414,"tag":512,"props":5381,"children":5382},{"style":535},[5383],{"type":419,"value":4677},{"type":414,"tag":512,"props":5385,"children":5386},{"style":745},[5387],{"type":419,"value":457},{"type":414,"tag":512,"props":5389,"children":5390},{"style":1784},[5391],{"type":419,"value":5392},"AddAzureKeyVault",{"type":414,"tag":512,"props":5394,"children":5395},{"style":745},[5396],{"type":419,"value":4300},{"type":414,"tag":512,"props":5398,"children":5399},{"style":535},[5400],{"type":419,"value":5401},"keyVaultEndpoint",{"type":414,"tag":512,"props":5403,"children":5404},{"style":745},[5405],{"type":419,"value":4216},{"type":414,"tag":512,"props":5407,"children":5408},{"style":745},[5409],{"type":419,"value":5332},{"type":414,"tag":512,"props":5411,"children":5412},{"style":793},[5413],{"type":419,"value":5414}," DefaultAzureCredential",{"type":414,"tag":512,"props":5416,"children":5417},{"style":745},[5418],{"type":419,"value":5419},"());\n",{"type":414,"tag":512,"props":5421,"children":5422},{"class":514,"line":900},[5423],{"type":414,"tag":512,"props":5424,"children":5425},{"style":745},[5426],{"type":419,"value":5427},"        })\n",{"type":414,"tag":512,"props":5429,"children":5430},{"class":514,"line":909},[5431,5435,5440,5444,5449],{"type":414,"tag":512,"props":5432,"children":5433},{"style":745},[5434],{"type":419,"value":5274},{"type":414,"tag":512,"props":5436,"children":5437},{"style":1784},[5438],{"type":419,"value":5439},"ConfigureWebHostDefaults",{"type":414,"tag":512,"props":5441,"children":5442},{"style":745},[5443],{"type":419,"value":4300},{"type":414,"tag":512,"props":5445,"children":5446},{"style":793},[5447],{"type":419,"value":5448},"webBuilder",{"type":414,"tag":512,"props":5450,"children":5451},{"style":745},[5452],{"type":419,"value":4230},{"type":414,"tag":512,"props":5454,"children":5455},{"class":514,"line":1431},[5456],{"type":414,"tag":512,"props":5457,"children":5458},{"style":745},[5459],{"type":419,"value":4669},{"type":414,"tag":512,"props":5461,"children":5462},{"class":514,"line":3358},[5463,5468,5472,5477,5482,5487],{"type":414,"tag":512,"props":5464,"children":5465},{"style":535},[5466],{"type":419,"value":5467},"            webBuilder",{"type":414,"tag":512,"props":5469,"children":5470},{"style":745},[5471],{"type":419,"value":457},{"type":414,"tag":512,"props":5473,"children":5474},{"style":1784},[5475],{"type":419,"value":5476},"UseStartup",{"type":414,"tag":512,"props":5478,"children":5479},{"style":745},[5480],{"type":419,"value":5481},"\u003C",{"type":414,"tag":512,"props":5483,"children":5484},{"style":793},[5485],{"type":419,"value":5486},"Startup",{"type":414,"tag":512,"props":5488,"children":5489},{"style":745},[5490],{"type":419,"value":5491},">();\n",{"type":414,"tag":512,"props":5493,"children":5494},{"class":514,"line":3367},[5495],{"type":414,"tag":512,"props":5496,"children":5497},{"style":745},[5498],{"type":419,"value":5499},"        });\n",{"type":414,"tag":415,"props":5501,"children":5502},{},[5503],{"type":419,"value":5504},"Vaults are generally cheap and anyway it is not as if security was an optional feature we should choose to add or not, therefore there is no reason not to use a vault to keep your secrets safe.",{"type":414,"tag":459,"props":5506,"children":5508},{"id":5507},"how-to-share-configuration-between-different-applications",[5509],{"type":419,"value":5510},"How to share configuration between different applications?",{"type":414,"tag":415,"props":5512,"children":5513},{},[5514,5516,5523],{"type":419,"value":5515},"There is a specific Azure component for that which is ",{"type":414,"tag":422,"props":5517,"children":5520},{"href":5518,"rel":5519},"https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview",[426],[5521],{"type":419,"value":5522},"Azure App Configuration",{"type":419,"value":5524},". It provides you a centralized place to manage your configuration for different applications, environments and locations. It also provides you other interesting features like the ability to dynamically change the value of an application setting without the need to restart this application.",{"type":414,"tag":415,"props":5526,"children":5527},{},[5528],{"type":414,"tag":609,"props":5529,"children":5533},{"alt":5530,"className":5531,"src":5532},"Configuration explorer in an Azure App Configuration resource.",[613,614],"/posts/images/lostinconfiguration_appconfig_1.png",[],{"type":414,"tag":415,"props":5535,"children":5536},{},[5537],{"type":419,"value":5538},"Azure App Configuration has its configuration provider that you can register like that:",{"type":414,"tag":503,"props":5540,"children":5542},{"className":4179,"code":5541,"language":326,"meta":401,"style":401},"public static IHostBuilder CreateHostBuilder(string[] args) =>\n    Host.CreateDefaultBuilder()\n        .ConfigureAppConfiguration((context, config) =>\n        {\n            var settings = config.Build();\n            var appConfigurationConnectionUri = new Uri(settings.GetValue\u003Cstring>(\"Endpoints:AppConfig\"));\n            config.AddAzureAppConfiguration(options =>\n            {\n                options.Connect(appConfigurationConnectionUri, new DefaultAzureCredential());\n            });\n        })\n        .ConfigureWebHostDefaults(webBuilder =>\n        {\n            webBuilder.UseStartup\u003CStartup>();\n        });\n",[5543],{"type":414,"tag":479,"props":5544,"children":5545},{"__ignoreMap":401},[5546,5589,5608,5643,5650,5683,5755,5784,5792,5834,5842,5849,5872,5879,5906],{"type":414,"tag":512,"props":5547,"children":5548},{"class":514,"line":515},[5549,5553,5557,5561,5565,5569,5573,5577,5581,5585],{"type":414,"tag":512,"props":5550,"children":5551},{"style":759},[5552],{"type":419,"value":5203},{"type":414,"tag":512,"props":5554,"children":5555},{"style":759},[5556],{"type":419,"value":5208},{"type":414,"tag":512,"props":5558,"children":5559},{"style":793},[5560],{"type":419,"value":5213},{"type":414,"tag":512,"props":5562,"children":5563},{"style":1784},[5564],{"type":419,"value":5218},{"type":414,"tag":512,"props":5566,"children":5567},{"style":745},[5568],{"type":419,"value":4300},{"type":414,"tag":512,"props":5570,"children":5571},{"style":745},[5572],{"type":419,"value":5227},{"type":414,"tag":512,"props":5574,"children":5575},{"style":745},[5576],{"type":419,"value":5232},{"type":414,"tag":512,"props":5578,"children":5579},{"style":793},[5580],{"type":419,"value":5237},{"type":414,"tag":512,"props":5582,"children":5583},{"style":745},[5584],{"type":419,"value":1333},{"type":414,"tag":512,"props":5586,"children":5587},{"style":745},[5588],{"type":419,"value":4230},{"type":414,"tag":512,"props":5590,"children":5591},{"class":514,"line":525},[5592,5596,5600,5604],{"type":414,"tag":512,"props":5593,"children":5594},{"style":535},[5595],{"type":419,"value":5253},{"type":414,"tag":512,"props":5597,"children":5598},{"style":745},[5599],{"type":419,"value":457},{"type":414,"tag":512,"props":5601,"children":5602},{"style":1784},[5603],{"type":419,"value":4875},{"type":414,"tag":512,"props":5605,"children":5606},{"style":745},[5607],{"type":419,"value":5266},{"type":414,"tag":512,"props":5609,"children":5610},{"class":514,"line":775},[5611,5615,5619,5623,5627,5631,5635,5639],{"type":414,"tag":512,"props":5612,"children":5613},{"style":745},[5614],{"type":419,"value":5274},{"type":414,"tag":512,"props":5616,"children":5617},{"style":1784},[5618],{"type":419,"value":4201},{"type":414,"tag":512,"props":5620,"children":5621},{"style":745},[5622],{"type":419,"value":4206},{"type":414,"tag":512,"props":5624,"children":5625},{"style":793},[5626],{"type":419,"value":5287},{"type":414,"tag":512,"props":5628,"children":5629},{"style":745},[5630],{"type":419,"value":4216},{"type":414,"tag":512,"props":5632,"children":5633},{"style":793},[5634],{"type":419,"value":4221},{"type":414,"tag":512,"props":5636,"children":5637},{"style":745},[5638],{"type":419,"value":1333},{"type":414,"tag":512,"props":5640,"children":5641},{"style":745},[5642],{"type":419,"value":4230},{"type":414,"tag":512,"props":5644,"children":5645},{"class":514,"line":784},[5646],{"type":414,"tag":512,"props":5647,"children":5648},{"style":745},[5649],{"type":419,"value":4669},{"type":414,"tag":512,"props":5651,"children":5652},{"class":514,"line":827},[5653,5657,5662,5666,5670,5674,5679],{"type":414,"tag":512,"props":5654,"children":5655},{"style":793},[5656],{"type":419,"value":5318},{"type":414,"tag":512,"props":5658,"children":5659},{"style":793},[5660],{"type":419,"value":5661}," settings",{"type":414,"tag":512,"props":5663,"children":5664},{"style":745},[5665],{"type":419,"value":4255},{"type":414,"tag":512,"props":5667,"children":5668},{"style":535},[5669],{"type":419,"value":4221},{"type":414,"tag":512,"props":5671,"children":5672},{"style":745},[5673],{"type":419,"value":457},{"type":414,"tag":512,"props":5675,"children":5676},{"style":1784},[5677],{"type":419,"value":5678},"Build",{"type":414,"tag":512,"props":5680,"children":5681},{"style":745},[5682],{"type":419,"value":4768},{"type":414,"tag":512,"props":5684,"children":5685},{"class":514,"line":865},[5686,5690,5695,5699,5703,5707,5711,5716,5720,5725,5729,5733,5738,5742,5747,5751],{"type":414,"tag":512,"props":5687,"children":5688},{"style":793},[5689],{"type":419,"value":5318},{"type":414,"tag":512,"props":5691,"children":5692},{"style":793},[5693],{"type":419,"value":5694}," appConfigurationConnectionUri",{"type":414,"tag":512,"props":5696,"children":5697},{"style":745},[5698],{"type":419,"value":4255},{"type":414,"tag":512,"props":5700,"children":5701},{"style":745},[5702],{"type":419,"value":5332},{"type":414,"tag":512,"props":5704,"children":5705},{"style":793},[5706],{"type":419,"value":5337},{"type":414,"tag":512,"props":5708,"children":5709},{"style":745},[5710],{"type":419,"value":4300},{"type":414,"tag":512,"props":5712,"children":5713},{"style":535},[5714],{"type":419,"value":5715},"settings",{"type":414,"tag":512,"props":5717,"children":5718},{"style":745},[5719],{"type":419,"value":457},{"type":414,"tag":512,"props":5721,"children":5722},{"style":1784},[5723],{"type":419,"value":5724},"GetValue",{"type":414,"tag":512,"props":5726,"children":5727},{"style":745},[5728],{"type":419,"value":5481},{"type":414,"tag":512,"props":5730,"children":5731},{"style":745},[5732],{"type":419,"value":5227},{"type":414,"tag":512,"props":5734,"children":5735},{"style":745},[5736],{"type":419,"value":5737},">(",{"type":414,"tag":512,"props":5739,"children":5740},{"style":745},[5741],{"type":419,"value":767},{"type":414,"tag":512,"props":5743,"children":5744},{"style":812},[5745],{"type":419,"value":5746},"Endpoints:AppConfig",{"type":414,"tag":512,"props":5748,"children":5749},{"style":745},[5750],{"type":419,"value":767},{"type":414,"tag":512,"props":5752,"children":5753},{"style":745},[5754],{"type":419,"value":4630},{"type":414,"tag":512,"props":5756,"children":5757},{"class":514,"line":900},[5758,5762,5766,5771,5775,5780],{"type":414,"tag":512,"props":5759,"children":5760},{"style":535},[5761],{"type":419,"value":4677},{"type":414,"tag":512,"props":5763,"children":5764},{"style":745},[5765],{"type":419,"value":457},{"type":414,"tag":512,"props":5767,"children":5768},{"style":1784},[5769],{"type":419,"value":5770},"AddAzureAppConfiguration",{"type":414,"tag":512,"props":5772,"children":5773},{"style":745},[5774],{"type":419,"value":4300},{"type":414,"tag":512,"props":5776,"children":5777},{"style":793},[5778],{"type":419,"value":5779},"options",{"type":414,"tag":512,"props":5781,"children":5782},{"style":745},[5783],{"type":419,"value":4230},{"type":414,"tag":512,"props":5785,"children":5786},{"class":514,"line":909},[5787],{"type":414,"tag":512,"props":5788,"children":5789},{"style":745},[5790],{"type":419,"value":5791},"            {\n",{"type":414,"tag":512,"props":5793,"children":5794},{"class":514,"line":1431},[5795,5800,5804,5809,5813,5818,5822,5826,5830],{"type":414,"tag":512,"props":5796,"children":5797},{"style":535},[5798],{"type":419,"value":5799},"                options",{"type":414,"tag":512,"props":5801,"children":5802},{"style":745},[5803],{"type":419,"value":457},{"type":414,"tag":512,"props":5805,"children":5806},{"style":1784},[5807],{"type":419,"value":5808},"Connect",{"type":414,"tag":512,"props":5810,"children":5811},{"style":745},[5812],{"type":419,"value":4300},{"type":414,"tag":512,"props":5814,"children":5815},{"style":535},[5816],{"type":419,"value":5817},"appConfigurationConnectionUri",{"type":414,"tag":512,"props":5819,"children":5820},{"style":745},[5821],{"type":419,"value":4216},{"type":414,"tag":512,"props":5823,"children":5824},{"style":745},[5825],{"type":419,"value":5332},{"type":414,"tag":512,"props":5827,"children":5828},{"style":793},[5829],{"type":419,"value":5414},{"type":414,"tag":512,"props":5831,"children":5832},{"style":745},[5833],{"type":419,"value":5419},{"type":414,"tag":512,"props":5835,"children":5836},{"class":514,"line":3358},[5837],{"type":414,"tag":512,"props":5838,"children":5839},{"style":745},[5840],{"type":419,"value":5841},"            });\n",{"type":414,"tag":512,"props":5843,"children":5844},{"class":514,"line":3367},[5845],{"type":414,"tag":512,"props":5846,"children":5847},{"style":745},[5848],{"type":419,"value":5427},{"type":414,"tag":512,"props":5850,"children":5851},{"class":514,"line":3434},[5852,5856,5860,5864,5868],{"type":414,"tag":512,"props":5853,"children":5854},{"style":745},[5855],{"type":419,"value":5274},{"type":414,"tag":512,"props":5857,"children":5858},{"style":1784},[5859],{"type":419,"value":5439},{"type":414,"tag":512,"props":5861,"children":5862},{"style":745},[5863],{"type":419,"value":4300},{"type":414,"tag":512,"props":5865,"children":5866},{"style":793},[5867],{"type":419,"value":5448},{"type":414,"tag":512,"props":5869,"children":5870},{"style":745},[5871],{"type":419,"value":4230},{"type":414,"tag":512,"props":5873,"children":5874},{"class":514,"line":3443},[5875],{"type":414,"tag":512,"props":5876,"children":5877},{"style":745},[5878],{"type":419,"value":4669},{"type":414,"tag":512,"props":5880,"children":5881},{"class":514,"line":3527},[5882,5886,5890,5894,5898,5902],{"type":414,"tag":512,"props":5883,"children":5884},{"style":535},[5885],{"type":419,"value":5467},{"type":414,"tag":512,"props":5887,"children":5888},{"style":745},[5889],{"type":419,"value":457},{"type":414,"tag":512,"props":5891,"children":5892},{"style":1784},[5893],{"type":419,"value":5476},{"type":414,"tag":512,"props":5895,"children":5896},{"style":745},[5897],{"type":419,"value":5481},{"type":414,"tag":512,"props":5899,"children":5900},{"style":793},[5901],{"type":419,"value":5486},{"type":414,"tag":512,"props":5903,"children":5904},{"style":745},[5905],{"type":419,"value":5491},{"type":414,"tag":512,"props":5907,"children":5908},{"class":514,"line":3547},[5909],{"type":414,"tag":512,"props":5910,"children":5911},{"style":745},[5912],{"type":419,"value":5499},{"type":414,"tag":459,"props":5914,"children":5916},{"id":5915},"which-configuration-provider-can-help-me-to-use-ab-testing-and-feature-flags-in-my-code",[5917],{"type":419,"value":5918},"Which configuration provider can help me to use A/B testing and feature flags in my code?",{"type":414,"tag":415,"props":5920,"children":5921},{},[5922,5927],{"type":414,"tag":422,"props":5923,"children":5925},{"href":5518,"rel":5924},[426],[5926],{"type":419,"value":5522},{"type":419,"value":5928}," is also the configuration provider to use when you want to use A/B testing or feature flags.\nThere are probably other configuration providers that allow you to do that but this is the one I know.",{"type":414,"tag":459,"props":5930,"children":5932},{"id":5931},"what-is-the-point-of-using-the-launchsettingsjson-file",[5933,5935,5941],{"type":419,"value":5934},"What is the point of using the ",{"type":414,"tag":479,"props":5936,"children":5938},{"className":5937},[],[5939],{"type":419,"value":5940},"launchsettings.json",{"type":419,"value":5942}," file?",{"type":414,"tag":415,"props":5944,"children":5945},{},[5946,5948,5953,5955,5960,5962,5967,5969,5975,5977,5982,5984,5989],{"type":419,"value":5947},"Unlike the ",{"type":414,"tag":479,"props":5949,"children":5951},{"className":5950},[],[5952],{"type":419,"value":5086},{"type":419,"value":5954}," files, the ",{"type":414,"tag":479,"props":5956,"children":5958},{"className":5957},[],[5959],{"type":419,"value":5940},{"type":419,"value":5961}," file is not used when you build and deploy your application somewhere. It is only useful to debug your application code locally. The tools you use to run your application on your local machine (your IDE or the .NET Core CLI) will use the settings in this file to provide configuration to your apps through environments variables or command line arguments. By default, this file will set the ",{"type":414,"tag":479,"props":5963,"children":5965},{"className":5964},[],[5966],{"type":419,"value":5094},{"type":419,"value":5968}," environment variable (or ",{"type":414,"tag":479,"props":5970,"children":5972},{"className":5971},[],[5973],{"type":419,"value":5974},"DOTNET_ENVIRONMENT",{"type":419,"value":5976}," depending on whether your application is an ASP.NET Core application or not) to ",{"type":414,"tag":479,"props":5978,"children":5980},{"className":5979},[],[5981],{"type":419,"value":4101},{"type":419,"value":5983}," so that you debug your code with the ",{"type":414,"tag":479,"props":5985,"children":5987},{"className":5986},[],[5988],{"type":419,"value":4101},{"type":419,"value":5990}," configuration",{"type":414,"tag":415,"props":5992,"children":5993},{},[5994],{"type":414,"tag":609,"props":5995,"children":5999},{"alt":5996,"className":5997,"src":5998},"Example of a launchsettings.json file.",[613,614],"/posts/images/lostinconfiguration_launchsettings_1.png",[],{"type":414,"tag":623,"props":6001,"children":6002},{"icon":625},[6003],{"type":414,"tag":415,"props":6004,"children":6005},{},[6006,6008,6013,6015,6021,6023,6029],{"type":419,"value":6007},"You can define multiple profiles in the ",{"type":414,"tag":479,"props":6009,"children":6011},{"className":6010},[],[6012],{"type":419,"value":5940},{"type":419,"value":6014}," file to be able to run your application with multiple configurations. It can be interesting to create a ",{"type":414,"tag":479,"props":6016,"children":6018},{"className":6017},[],[6019],{"type":419,"value":6020},"Staging profile",{"type":419,"value":6022}," to debug your application with the ",{"type":414,"tag":479,"props":6024,"children":6026},{"className":6025},[],[6027],{"type":419,"value":6028},"Staging",{"type":419,"value":6030}," configuration; for instance to reproduce a bug that only happens in Staging environment.",{"type":414,"tag":459,"props":6032,"children":6034},{"id":6033},"lets-recap",[6035],{"type":419,"value":6036},"Let's recap.",{"type":414,"tag":415,"props":6038,"children":6039},{},[6040],{"type":419,"value":6041},"To know where to put your settings in an ASP.NET Core project you have to ask yourself some questions: is this setting secret or not, does its value depends on the environment, will it be shared with other applications... ?",{"type":414,"tag":415,"props":6043,"children":6044},{},[6045],{"type":419,"value":6046},"My point of view about how to handle the configuration in an ASP.NET Core project is the following:",{"type":414,"tag":1518,"props":6048,"children":6049},{},[6050,6062,6075,6080,6092,6104],{"type":414,"tag":1522,"props":6051,"children":6052},{},[6053,6055,6060],{"type":419,"value":6054},"put all your settings in the ",{"type":414,"tag":479,"props":6056,"children":6058},{"className":6057},[],[6059],{"type":419,"value":4339},{"type":419,"value":6061}," file (without necessarily putting the values of the settings) to have a global view of the configuration used by your application",{"type":414,"tag":1522,"props":6063,"children":6064},{},[6065,6067,6073],{"type":419,"value":6066},"keep a ",{"type":414,"tag":479,"props":6068,"children":6070},{"className":6069},[],[6071],{"type":419,"value":6072},"appsettings.{EnvironmentName}.json",{"type":419,"value":6074}," file by environment in your project with only the settings that are dependent on the environment",{"type":414,"tag":1522,"props":6076,"children":6077},{},[6078],{"type":419,"value":6079},"never store secrets in source code and use an Azure Key Vault to store the settings that are secrets",{"type":414,"tag":1522,"props":6081,"children":6082},{},[6083,6085,6090],{"type":419,"value":6084},"create different profiles in your ",{"type":414,"tag":479,"props":6086,"children":6088},{"className":6087},[],[6089],{"type":419,"value":5940},{"type":419,"value":6091},"file to debug your application locally with different configurations",{"type":414,"tag":1522,"props":6093,"children":6094},{},[6095,6097,6102],{"type":419,"value":6096},"use environment variables (through ",{"type":414,"tag":479,"props":6098,"children":6100},{"className":6099},[],[6101],{"type":419,"value":5940},{"type":419,"value":6103}," locally and application settings in Azure) to override settings previously defined in other configuration sources",{"type":414,"tag":1522,"props":6105,"children":6106},{},[6107],{"type":419,"value":6108},"think about Azure App Configuration if you need to share some settings among different applications",{"type":414,"tag":415,"props":6110,"children":6111},{},[6112],{"type":419,"value":6113},"I hope this article has answered some of your questions about configuration ASP.NET Core and that you feel less lost now. Have fun with configuration providers!",{"type":414,"tag":1469,"props":6115,"children":6116},{},[6117],{"type":419,"value":1473},{"title":401,"searchDepth":525,"depth":525,"links":6119},[6120,6121,6122,6123,6124,6125,6126,6127,6128,6130],{"id":4121,"depth":525,"text":4124},{"id":4146,"depth":525,"text":4149},{"id":4945,"depth":525,"text":4948},{"id":5018,"depth":525,"text":5021},{"id":5043,"depth":525,"text":5046},{"id":5123,"depth":525,"text":5126},{"id":5507,"depth":525,"text":5510},{"id":5915,"depth":525,"text":5918},{"id":5931,"depth":525,"text":6129},"What is the point of using the launchsettings.json file?",{"id":6033,"depth":525,"text":6036},"content:1.posts:24.lost-in-configuration.md","1.posts/24.lost-in-configuration.md",{"_path":37,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":36,"description":6134,"lead":6135,"date":6136,"image":6137,"badge":6139,"tags":6140,"body":6141,"_type":1480,"_id":6526,"_source":1482,"_file":6527,"_extension":1484},"The possibility to add configuration sources in Azure Functions has just been released with the latest version of Microsoft.Azure.Functions.Extensions NuGet package. I have been waiting for this feature for a long time (like many people I think) because it brings to Azure Functions all the things we are used to with configuration in ASP.NET Core 😻. But that is not the only reason, it is also because with this feature you almost don't need to use key vault references!","Talking about how to manage configuration secrets in Azure Functions.","2020-09-21T00:00:00.000Z",{"src":6138},"/images/lightning_1.jpg",{"label":4101},[257,260,228,263],{"type":411,"children":6142,"toc":6518},[6143,6165,6170,6176,6203,6212,6226,6235,6240,6246,6258,6263,6272,6277,6328,6340,6349,6354,6367,6379,6422,6431,6436,6445,6450,6456,6492,6500,6505,6509,6514],{"type":414,"tag":415,"props":6144,"children":6145},{},[6146,6148,6154,6156,6163],{"type":419,"value":6147},"The possibility to add configuration sources in Azure Functions has just been released with the latest version of ",{"type":414,"tag":479,"props":6149,"children":6151},{"className":6150},[],[6152],{"type":419,"value":6153},"Microsoft.Azure.Functions.Extensions",{"type":419,"value":6155}," ",{"type":414,"tag":422,"props":6157,"children":6160},{"href":6158,"rel":6159},"https://www.nuget.org/packages/Microsoft.Azure.Functions.Extensions/1.1.0",[426],[6161],{"type":419,"value":6162},"NuGet package",{"type":419,"value":6164},". I have been waiting for this feature for a long time (like many people I think) because it brings to Azure Functions all the things we are used to with configuration in ASP.NET Core 😻. But that is not the only reason, it is also because with this feature you almost don't need to use key vault references!",{"type":414,"tag":415,"props":6166,"children":6167},{},[6168],{"type":419,"value":6169},"But before deep dive into this topic, let's give a bit of context about configuration and secrets in Azure Functions (just skip the next section if you already are familiar with all that).",{"type":414,"tag":459,"props":6171,"children":6173},{"id":6172},"a-quick-reminder-about-configuration-and-secrets-in-azure-functions",[6174],{"type":419,"value":6175},"A quick reminder about configuration and secrets in Azure Functions",{"type":414,"tag":415,"props":6177,"children":6178},{},[6179,6181,6186,6188,6194,6196,6201],{"type":419,"value":6180},"Configuration used by functions in a Function App is stored in settings that can be set in the ",{"type":414,"tag":479,"props":6182,"children":6184},{"className":6183},[],[6185],{"type":419,"value":263},{"type":419,"value":6187}," section of a Function App in Azure Portal. When developing locally you have to use a ",{"type":414,"tag":479,"props":6189,"children":6191},{"className":6190},[],[6192],{"type":419,"value":6193},"local.settings.json",{"type":419,"value":6195}," file that will contain copies of the settings stored in Azure portal. The settings from ",{"type":414,"tag":479,"props":6197,"children":6199},{"className":6198},[],[6200],{"type":419,"value":6193},{"type":419,"value":6202}," will be loaded as environment variables when debugging locally. But as its name suggests, the purpose of this file is to be used for local development only: its settings are not used when the function runs on Azure. Furthermore, this file should never be committed to avoid putting settings corresponding to secrets in source control.",{"type":414,"tag":415,"props":6204,"children":6205},{},[6206],{"type":414,"tag":609,"props":6207,"children":6211},{"alt":6208,"className":6209,"src":6210},"Azure Function local settings file.",[613,614],"/posts/images/functionssecrets_localsettings_1.png",[],{"type":414,"tag":415,"props":6213,"children":6214},{},[6215,6217,6224],{"type":419,"value":6216},"Speaking of secrets, they should never be directly stored in the application settings of a Function App (the same goes for App Services by the way). Why not? Because secrets would be available to  anyone who has access to the Function App in the Azure Portal. The right way is to use an Azure Key Vault which is the Azure component for securely storing and accessing secrets 🔒. Once your secrets are in the key vault, you have to grant the Key Vault access to the identity of your Function App and you can then reference the secrets you need directly in your application settings. These are called ",{"type":414,"tag":422,"props":6218,"children":6221},{"href":6219,"rel":6220},"https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references",[426],[6222],{"type":419,"value":6223},"Key Vault references",{"type":419,"value":6225}," because an application setting does not contain directly the value of a secret but a reference to the secret which is stored in Key Vault. When running, your function will automatically have access to the secret and its value as an environment variable, as if it was a normal application setting.",{"type":414,"tag":415,"props":6227,"children":6228},{},[6229],{"type":414,"tag":609,"props":6230,"children":6234},{"alt":6231,"className":6232,"src":6233},"Function App application settings in Azure portal.",[613,614],"/posts/images/functionssecrets_portal_1.png",[],{"type":414,"tag":415,"props":6236,"children":6237},{},[6238],{"type":419,"value":6239},"Key Vault references work for both App Services and Function Apps and are particularly useful for existing applications that have their secrets stored in settings because securing the secrets with Azure Key Vault references does not require any code change.",{"type":414,"tag":459,"props":6241,"children":6243},{"id":6242},"the-downside-of-key-vault-references-the-local-debugging-experience",[6244],{"type":419,"value":6245},"The downside of Key Vault references: the local debugging experience",{"type":414,"tag":415,"props":6247,"children":6248},{},[6249,6251,6256],{"type":419,"value":6250},"Do you remember when I told you that the local settings file should not be committed to your git repository? Well, what you might not have realized is that it means when someone from your team clones the git repository containing your function he won't have this ",{"type":414,"tag":479,"props":6252,"children":6254},{"className":6253},[],[6255],{"type":419,"value":6193},{"type":419,"value":6257}," file which is mandatory to run your function app locally. And even if he creates manually the file, he will not necessarily know which settings to put in it. But we want to avoid him manually copying all the settings from the Azure portal or asking a colleague to send his local settings file by email (which is a really bad practice if it contains secrets). Hopefully, there are some ways to fill or generate this file.",{"type":414,"tag":415,"props":6259,"children":6260},{},[6261],{"type":419,"value":6262},"If you use Visual Studio there is a GUI that will help you compare/modify local settings and Azure settings.",{"type":414,"tag":415,"props":6264,"children":6265},{},[6266],{"type":414,"tag":609,"props":6267,"children":6271},{"alt":6268,"className":6269,"src":6270},"Function App application settings in Visual Studio.",[613,614],"/posts/images/functionssecrets_vs_1.png",[],{"type":414,"tag":415,"props":6273,"children":6274},{},[6275],{"type":419,"value":6276},"And whether or not you are using Visual Studio, you can generate the local settings file filled with Azure settings with a few Azure Functions CLI commands:",{"type":414,"tag":503,"props":6278,"children":6280},{"className":1912,"code":6279,"language":1914,"meta":401,"style":401},"func azure functionapp fetch-app-settings $FUNCTION_APP_NAME\nfunc settings decrypt\n",[6281],{"type":414,"tag":479,"props":6282,"children":6283},{"__ignoreMap":401},[6284,6312],{"type":414,"tag":512,"props":6285,"children":6286},{"class":514,"line":515},[6287,6292,6297,6302,6307],{"type":414,"tag":512,"props":6288,"children":6289},{"style":793},[6290],{"type":419,"value":6291},"func",{"type":414,"tag":512,"props":6293,"children":6294},{"style":812},[6295],{"type":419,"value":6296}," azure",{"type":414,"tag":512,"props":6298,"children":6299},{"style":812},[6300],{"type":419,"value":6301}," functionapp",{"type":414,"tag":512,"props":6303,"children":6304},{"style":812},[6305],{"type":419,"value":6306}," fetch-app-settings",{"type":414,"tag":512,"props":6308,"children":6309},{"style":535},[6310],{"type":419,"value":6311}," $FUNCTION_APP_NAME\n",{"type":414,"tag":512,"props":6313,"children":6314},{"class":514,"line":525},[6315,6319,6323],{"type":414,"tag":512,"props":6316,"children":6317},{"style":793},[6318],{"type":419,"value":6291},{"type":414,"tag":512,"props":6320,"children":6321},{"style":812},[6322],{"type":419,"value":5661},{"type":414,"tag":512,"props":6324,"children":6325},{"style":812},[6326],{"type":419,"value":6327}," decrypt\n",{"type":414,"tag":415,"props":6329,"children":6330},{},[6331,6333,6338],{"type":419,"value":6332},"This is an example of a generated ",{"type":414,"tag":479,"props":6334,"children":6336},{"className":6335},[],[6337],{"type":419,"value":6193},{"type":419,"value":6339}," file:",{"type":414,"tag":415,"props":6341,"children":6342},{},[6343],{"type":414,"tag":609,"props":6344,"children":6348},{"alt":6345,"className":6346,"src":6347},"Generated local settings file.",[613,614],"/posts/images/functionssecrets_localsettings_2.png",[],{"type":414,"tag":415,"props":6350,"children":6351},{},[6352],{"type":419,"value":6353},"However, as you can see, the settings corresponding to secrets contain the Key Vault reference values that are used by Azure to link the settings to the secrets. But this is an Azure mechanism, locally the true secrets value won't be loaded into configuration. So you will have to manually retrieve the value of the secrets in your key vault and set them manually in your local settings file. That may be okay for one secret but that gets quickly annoying when you have many secrets. You don't want your team members to constantly lose time copying secret values from the key vault on their local environment. I don't even talk about the loss of time understanding what is wrong when a secret value has changed and you did not realize it or the bad habits it could lead to like sending secrets by email or chat messages.",{"type":414,"tag":415,"props":6355,"children":6356},{},[6357,6359,6366],{"type":419,"value":6358},"This is a terrible local debugging experience and honestly, you don't want that. What you want is that your function code just works when you or one of your colleagues clones or pulls a new version of the function app code. When debugging locally the code of an ASP.NET Core application deployed in an App Service you don't have this kind of problem because usually your code directly loads the secrets from the Key Vault thanks to ",{"type":414,"tag":422,"props":6360,"children":6363},{"href":6361,"rel":6362},"https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?view=aspnetcore-3.1",[426],[6364],{"type":419,"value":6365},"Key Vault configuration provider",{"type":419,"value":457},{"type":414,"tag":459,"props":6368,"children":6370},{"id":6369},"here-comes-ifunctionsconfigurationbuilder",[6371,6373],{"type":419,"value":6372},"Here comes ",{"type":414,"tag":479,"props":6374,"children":6376},{"className":6375},[],[6377],{"type":419,"value":6378},"IFunctionsConfigurationBuilder",{"type":414,"tag":415,"props":6380,"children":6381},{},[6382,6384,6389,6391,6397,6399,6406,6408,6413,6415,6420],{"type":419,"value":6383},"If you are already familiar with dependency injection in Azure Functions, you already know the ",{"type":414,"tag":479,"props":6385,"children":6387},{"className":6386},[],[6388],{"type":419,"value":6153},{"type":419,"value":6390}," NuGet package that allows you to inherit from the ",{"type":414,"tag":479,"props":6392,"children":6394},{"className":6393},[],[6395],{"type":419,"value":6396},"FunctionStartup",{"type":419,"value":6398}," abstract class and register the different services you want to inject into your functions (you can find more about that in the ",{"type":414,"tag":422,"props":6400,"children":6403},{"href":6401,"rel":6402},"https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection",[426],[6404],{"type":419,"value":6405},"documentation",{"type":419,"value":6407},"). In the latest version of this NuGet package, a new virtual method has been added to ",{"type":414,"tag":479,"props":6409,"children":6411},{"className":6410},[],[6412],{"type":419,"value":6396},{"type":419,"value":6414},": ",{"type":414,"tag":479,"props":6416,"children":6418},{"className":6417},[],[6419],{"type":419,"value":4201},{"type":419,"value":6421},". It allows you to specify additional configuration sources you would need in your functions.",{"type":414,"tag":415,"props":6423,"children":6424},{},[6425],{"type":414,"tag":609,"props":6426,"children":6430},{"alt":6427,"className":6428,"src":6429},"FunctionsStartup abstract class.",[613,614],"/posts/images/functionssecrets_vs_2.png",[],{"type":414,"tag":415,"props":6432,"children":6433},{},[6434],{"type":419,"value":6435},"What is awesome is that you can use all the configuration providers you are used to in ASP.NET Core and that includes the Key Vault Configuration provider. I think you understand what I am getting at 😉: instead of using key vault references in your function app settings, you can simply retrieve the secrets from your key vault thanks to the configuration provider.",{"type":414,"tag":415,"props":6437,"children":6438},{},[6439],{"type":414,"tag":609,"props":6440,"children":6444},{"alt":6441,"className":6442,"src":6443},"Debugging configuration in Startup file in Visual Studio.",[613,614],"/posts/images/functionssecrets_vs_3.png",[],{"type":414,"tag":415,"props":6446,"children":6447},{},[6448],{"type":419,"value":6449},"This way, no more copying secret, no more storing secrets values locally, no more wondering if you have the latest version of a secret. Say goodbye to key vault references, pull the latest version of your code, press F5 and it will work!",{"type":414,"tag":459,"props":6451,"children":6453},{"id":6452},"the-triggers-case",[6454],{"type":419,"value":6455},"The triggers case",{"type":414,"tag":415,"props":6457,"children":6458},{},[6459,6461,6475,6477,6481,6483,6490],{"type":419,"value":6460},"Well in my title I said ",{"type":414,"tag":6462,"props":6463,"children":6464},"em",{},[6465,6467,6473],{"type":419,"value":6466},"\"you ",{"type":414,"tag":6468,"props":6469,"children":6470},"strong",{},[6471],{"type":419,"value":6472},"almost",{"type":419,"value":6474}," no longer need key vault references\"",{"type":419,"value":6476}," and the ",{"type":414,"tag":6468,"props":6478,"children":6479},{},[6480],{"type":419,"value":6472},{"type":419,"value":6482}," is important. As the ",{"type":414,"tag":422,"props":6484,"children":6487},{"href":6485,"rel":6486},"https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources",[426],[6488],{"type":419,"value":6489},"Azure Functions documentation",{"type":419,"value":6491}," about customizing configuration sources mentions:",{"type":414,"tag":623,"props":6493,"children":6494},{"icon":658},[6495],{"type":414,"tag":415,"props":6496,"children":6497},{},[6498],{"type":419,"value":6499},"For function apps running in the Consumption or Premium plans, modifications to configuration values used in triggers can cause scaling errors. Any changes to these properties by the FunctionsStartup class result in a function app startup error.",{"type":414,"tag":415,"props":6501,"children":6502},{},[6503],{"type":419,"value":6504},"Therefore, if you use a trigger that needs a secret (the connection string of an EventHub trigger for instance), you have no other choice than to use a key vault reference. But for everything else you are good to go with Azure Key Vault configuration provider.",{"type":414,"tag":459,"props":6506,"children":6507},{"id":3111},[6508],{"type":419,"value":3114},{"type":414,"tag":415,"props":6510,"children":6511},{},[6512],{"type":419,"value":6513},"To summarize, after a quick recall of how Azure Functions configuration works we have seen how Key Vault references can help to avoid having secret values in settings. We talked about the downside of this approach for the local development experience and how using the Azure Key Vault configuration provider solved that except when a secret is needed in a trigger.",{"type":414,"tag":1469,"props":6515,"children":6516},{},[6517],{"type":419,"value":1473},{"title":401,"searchDepth":525,"depth":525,"links":6519},[6520,6521,6522,6524,6525],{"id":6172,"depth":525,"text":6175},{"id":6242,"depth":525,"text":6245},{"id":6369,"depth":525,"text":6523},"Here comes IFunctionsConfigurationBuilder",{"id":6452,"depth":525,"text":6455},{"id":3111,"depth":525,"text":3114},"content:1.posts:10.azure-functions-custom-configuration.md","1.posts/10.azure-functions-custom-configuration.md",1716749600672]