diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..089c9674 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "appService.defaultWebAppToDeploy": "None" +} \ No newline at end of file diff --git a/demos/01-appservices/demo-01/create-webapps.azcli b/demos/01-appservices/demo-01/create-webapps.azcli index 33058fe6..d75562d2 100644 --- a/demos/01-appservices/demo-01/create-webapps.azcli +++ b/demos/01-appservices/demo-01/create-webapps.azcli @@ -1,22 +1,22 @@ -rnd=$RANDOM -grp=az204-m01-appservices-$rnd +env=$RANDOM +grp=az204-m01-appservices-$env loc=westeurope -appPlan=appservices-$rnd -mvcapp=mvcapp-$rnd +plan=appservices-$env +mvcapp=mvcapp-$env # create a resource group az group create -n $grp -l $loc # create an App Service plan -az appservice plan create -n $appPlan -g $grp --sku S1 +az appservice plan create -n $plan -g $grp --sku S1 # create cliapp -az webapp create -n cli-api-$rnd -g $grp --plan $appPlan --runtime "DOTNET|6.0" +az webapp create -n cli-api-$env -g $grp --plan $plan --runtime "DOTNET|6.0" # create mvcapp -az webapp create -n $mvcapp -g $grp --plan $appPlan --runtime "DOTNET|6.0" +az webapp create -n $mvcapp -g $grp --plan $plan --runtime "DOTNET|6.0" # create and upload mvcapp app using az webapp up cd mvc-app -az webapp up -n $mvcapp -g $grp -p $appPlan --sku F1 -l $loc -r "DOTNET|6.0" +az webapp up -n $mvcapp -g $grp -p $plan --sku F1 -l $loc -r "DOTNET|6.0" cd .. \ No newline at end of file diff --git a/demos/01-appservices/demo-01/mvc-app/.azure/config b/demos/01-appservices/demo-01/mvc-app/.azure/config new file mode 100644 index 00000000..537b50fe --- /dev/null +++ b/demos/01-appservices/demo-01/mvc-app/.azure/config @@ -0,0 +1,7 @@ +[defaults] +group = az204-m01-appservices-15443 +sku = F1 +appserviceplan = appservices-15443 +location = westeurope +web = mvcapp-15443 + diff --git a/demos/01-appservices/demo-01/readme.md b/demos/01-appservices/demo-01/readme.md index d92347a6..cb720c70 100644 --- a/demos/01-appservices/demo-01/readme.md +++ b/demos/01-appservices/demo-01/readme.md @@ -11,7 +11,7 @@ Use [.NET Core CLI](https://docs.microsoft.com/en-us/dotnet/core/tools/). Scaffold and run App: ```bash -dotnet new api -n cli-api +dotnet new webapi -n cli-api --framework net6.0 dotnet run ``` diff --git a/demos/01-appservices/demo-02/deploy-using-git.azcli b/demos/01-appservices/demo-02/deploy-using-git.azcli index c2d5c7e9..c40fe1aa 100644 --- a/demos/01-appservices/demo-02/deploy-using-git.azcli +++ b/demos/01-appservices/demo-02/deploy-using-git.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM -grp=az204-m01-gitdeploy-$rnd -appPlan=gitdeploy-$rnd -app=gitdeploy-website-$rnd +env=$RANDOM +grp=az204-m01-gitdeploy-$env +appPlan=gitdeploy-$env +app=gitdeploy-website-$env gitrepo="https://github.com/arambazamba/git-deploy-app" az group create -n $grp -l westeurope diff --git a/demos/01-appservices/demo-03/create-webapp.azcli b/demos/01-appservices/demo-03/create-webapp.azcli index 6ebd8fc4..3dc607a3 100644 --- a/demos/01-appservices/demo-03/create-webapp.azcli +++ b/demos/01-appservices/demo-03/create-webapp.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM -grp=az204-m01-appsettings-$rnd -plan=appsettings-$rnd -app=settings-api-$rnd +env=$RANDOM +grp=az204-m01-appsettings-$env +plan=appsettings-$env +app=settings-api-$env loc=westeurope az group create -n $grp -l $loc diff --git a/demos/01-appservices/demo-04/deploy-easy-auth.azcli b/demos/01-appservices/demo-04/deploy-easy-auth.azcli index e4e0f2a1..bfa63b3b 100644 --- a/demos/01-appservices/demo-04/deploy-easy-auth.azcli +++ b/demos/01-appservices/demo-04/deploy-easy-auth.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM -grp=az204-m01-easy-auth-$rnd -appPlan=easyauth-$rnd -app=easyauth-website-$rnd +env=$RANDOM +grp=az204-m01-easy-auth-$env +appPlan=easyauth-$env +app=easyauth-website-$env appregName=easyauth-app gitrepo="https://github.com/arambazamba/git-deploy-app" tenantID=d92b247e-90e0-4469-a129-6a32866c0d0a diff --git a/demos/01-appservices/demo-05/create-webapp-slots.azcli b/demos/01-appservices/demo-05/create-webapp-slots.azcli index d532ce29..2b964c46 100644 --- a/demos/01-appservices/demo-05/create-webapp-slots.azcli +++ b/demos/01-appservices/demo-05/create-webapp-slots.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM -grp=az204-m01-deployment-slots-$rnd -appPlan=deployment-slots-$rnd -app=deployment-slots-app-$rnd +env=$RANDOM +grp=az204-m01-deployment-slots-$env +appPlan=deployment-slots-$env +app=deployment-slots-app-$env loc=westeurope slot=staging diff --git a/demos/01-appservices/demo-06/traffic-manager.azcli b/demos/01-appservices/demo-06/traffic-manager.azcli index 52441028..ccf3bd47 100644 --- a/demos/01-appservices/demo-06/traffic-manager.azcli +++ b/demos/01-appservices/demo-06/traffic-manager.azcli @@ -1,8 +1,8 @@ -rnd=$RANDOM -eugrp=az204-tm-eu-$rnd -usgrp=az204-tm-us-$rnd -euplan=tm-westeur-$rnd -usplan=tm-eastus-$rnd +env=$RANDOM +eugrp=az204-tm-eu-$env +usgrp=az204-tm-us-$env +euplan=tm-westeur-$env +usplan=tm-eastus-$env gitrepo="https://github.com/arambazamba/git-deploy-app" user=labadmin pwd=Pa$$w0rd1234! @@ -22,13 +22,13 @@ az webapp deployment source config -n tmapp-$usplan -g $usgrp -u $gitrepo --bran usid=$(az webapp show -n tmapp-$usplan -g $usgrp --query id -o tsv) # Create TM Profile & Add Endpoints -az network traffic-manager profile create -g $eugrp -n tmprofile$rnd --routing-method Geographic \ - --unique-dns-name tmapp-$rnd --ttl 30 --protocol HTTP --port 80 --path "/" +az network traffic-manager profile create -g $eugrp -n tmprofile$env --routing-method Geographic \ + --unique-dns-name tmapp-$env --ttl 30 --protocol HTTP --port 80 --path "/" -az network traffic-manager endpoint create --name ep-$euplan -g $eugrp --profile-name tmprofile$rnd --geo-mapping GEO-EU \ +az network traffic-manager endpoint create --name ep-$euplan -g $eugrp --profile-name tmprofile$env --geo-mapping GEO-EU \ --type azureEndpoints --target-resource-id $euid --endpoint-status Enabled -az network traffic-manager endpoint create --name ep-$usplan -g $eugrp --profile-name tmprofile$rnd --geo-mapping GEO-NA \ +az network traffic-manager endpoint create --name ep-$usplan -g $eugrp --profile-name tmprofile$env --geo-mapping GEO-NA \ --type azureEndpoints --target-resource-id $usid --endpoint-status Enabled # Create a vm in the US to access the webapp with an us ip address diff --git a/demos/02-blob-storage/demo-01/create-blob-app.azcli b/demos/02-blob-storage/demo-01/create-blob-app.azcli index 5aa8c2d0..176a0dba 100644 --- a/demos/02-blob-storage/demo-01/create-blob-app.azcli +++ b/demos/02-blob-storage/demo-01/create-blob-app.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM -grp=az204-m02-foodpics-$rnd +env=$RANDOM +grp=az204-m02-foodpics-$env loc=westeurope -acct=foodpics$rnd +acct=foodpics$env container="food" blob_name=shrimp-vindaloo.jpg file_to_upload="./food-pics/shrimp-vindaloo.jpg" diff --git a/demos/02-blob-storage/demo-02/creata-sas-app.azcli b/demos/02-blob-storage/demo-02/creata-sas-app.azcli index 24197248..4972a8ea 100644 --- a/demos/02-blob-storage/demo-02/creata-sas-app.azcli +++ b/demos/02-blob-storage/demo-02/creata-sas-app.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM +env=$RANDOM loc=westeurope -grp=az204-m02-sas-$rnd -acct=medicalrecords$rnd +grp=az204-m02-sas-$env +acct=medicalrecords$env container="patient-images" path="./patient-images/" blob="patient-32589.jpg" diff --git a/demos/02-blob-storage/demo-03/create-fileshare.azcli b/demos/02-blob-storage/demo-03/create-fileshare.azcli index 913b3e45..b84ea377 100644 --- a/demos/02-blob-storage/demo-03/create-fileshare.azcli +++ b/demos/02-blob-storage/demo-03/create-fileshare.azcli @@ -1,7 +1,7 @@ -rnd=$RANDOM +env=$RANDOM grp=az-lab loc=westeurope -acct=labvm$rnd +acct=labvm$env az group create -n $grp -l $loc diff --git a/demos/07-secure-solutions/01-key-vault/create-db.azcli b/demos/07-secure-solutions/01-key-vault/create-db.azcli index 7d143779..281a2b4b 100644 --- a/demos/07-secure-solutions/01-key-vault/create-db.azcli +++ b/demos/07-secure-solutions/01-key-vault/create-db.azcli @@ -1,9 +1,9 @@ -rnd=dev -grp=az204-m07-secure-solutions-$rnd +env=dev +grp=az204-m07-secure-solutions-$env loc=westeurope -server=foodserver$rnd -db=foodb$rnd -vault=foodvault-$rnd +server=foodserver$env +db=foodb$env +vault=foodvault-$env user=$(az keyvault secret show --name "DBUser" --vault-name $vault --query value -o tsv) pwd=$(az keyvault secret show --name "DBPassword" --vault-name $vault --query value -o tsv) diff --git a/demos/07-secure-solutions/01-key-vault/create-vault.azcli b/demos/07-secure-solutions/01-key-vault/create-vault.azcli index 7e28672a..920ae80a 100644 --- a/demos/07-secure-solutions/01-key-vault/create-vault.azcli +++ b/demos/07-secure-solutions/01-key-vault/create-vault.azcli @@ -1,7 +1,7 @@ -rnd=dev -grp=az204-m07-secure-solutions-$rnd +env=dev +grp=az204-m07-secure-solutions-$env loc=westeurope -vault=foodvault-$rnd +vault=foodvault-$env az group create -n $grp -l $loc @@ -16,6 +16,9 @@ az keyvault secret set --vault-name $vault --name "DBPassword" --value "Lab@dmin az keyvault secret show --vault-name $vault --name "DBUser" user=$(az keyvault secret show --vault-name $vault --name "DBUser" --query value) +pwd=$(az keyvault secret show --vault-name $vault --name "DBPassword" --query value -o tsv) + +az keyvault secret set --vault-name $vault --name "conSQLServer" --value "Server=tcp:$server.database.windows.net,1433;Database=$db;User ID=$user;Password='$pwd';Encrypt=true;Connection Timeout=30;" az keyvault secret list --vault-name $vault -o table diff --git a/demos/07-secure-solutions/02-managed-identity/demo-01/appservice-use-mi.azcli b/demos/07-secure-solutions/02-managed-identity/demo-01/appservice-use-mi.azcli index c7d7cfa6..f701587e 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-01/appservice-use-mi.azcli +++ b/demos/07-secure-solutions/02-managed-identity/demo-01/appservice-use-mi.azcli @@ -1,9 +1,9 @@ -rnd=dev -grp=az204-m07-secure-solutions-$rnd +env=dev +grp=az204-m07-secure-solutions-$env loc=westeurope -vault=foodvault-$rnd -plan=foodplan-$rnd -app=foodapi-$rnd +vault=foodvault-$env +plan=foodplan-$env +app=foodapi-$env cd food-api-mi az webapp up -n $app -g $grp -p $plan -l $loc --sku Free -r "DOTNET|6.0" diff --git a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.gitignore b/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.gitignore index bea25d71..3be79d50 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.gitignore +++ b/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.gitignore @@ -6,6 +6,8 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +.azure/ + # Database *.db diff --git a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/Startup.cs b/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/Startup.cs index b844b7f8..87802064 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/Startup.cs +++ b/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/Startup.cs @@ -2,11 +2,10 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Azure.Identity; +using Azure.Security.KeyVault.Secrets; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.Azure.KeyVault; -using Microsoft.Azure.Services.AppAuthentication; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -31,13 +30,12 @@ public void ConfigureServices (IServiceCollection services) { //Use MI to get DB Con Str Console.WriteLine($"Using KeyVault: {cfg.Azure.KevVault}"); - var azureServiceTokenProvider = new AzureServiceTokenProvider(); - var kvClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)); - string dbconstring = (kvClient.GetSecretAsync($"https://{cfg.Azure.KevVault}", "conSQLite").Result).Value; - Console.WriteLine($"dbconstring from vault: {dbconstring}"); + var client = new SecretClient(new Uri($"https://{cfg.Azure.KevVault}"), new DefaultAzureCredential()); + var secret = client.GetSecret("conSQLite").Value; + Console.WriteLine($"dbconstring from vault: {secret.Value}"); //EF - services.AddDbContext (options => options.UseSqlite (cfg.ConnectionStrings.SqLiteDbConnection)); + services.AddDbContext (options => options.UseSqlite (secret.Value)); //Swagger services.AddSwaggerGen (c => { diff --git a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/food-api.csproj b/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/food-api.csproj index 106ad44e..dc622e24 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/food-api.csproj +++ b/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/food-api.csproj @@ -3,11 +3,11 @@ net6.0 - - - - - - + + + + + + \ No newline at end of file diff --git a/demos/07-secure-solutions/02-managed-identity/demo-02/vm-mi.azcli b/demos/07-secure-solutions/02-managed-identity/demo-02/vm-mi.azcli index faaa72db..c1703638 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-02/vm-mi.azcli +++ b/demos/07-secure-solutions/02-managed-identity/demo-02/vm-mi.azcli @@ -1,10 +1,10 @@ -rnd=dev -grp=az204-m07-secure-solutions-$rnd +env=dev +grp=az204-m07-secure-solutions-$env loc=westeurope -identity=ua-identity-$rnd -vm=identityvm-$rnd +identity=ua-identity-$env +vm=identityvm-$env admin=az204admin -vault=foodvault-$rnd +vault=foodvault-$env az group create -n $grp -l $loc diff --git a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/.gitignore b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/.gitignore index ff5b00c5..ad9b6e1b 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/.gitignore +++ b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/.gitignore @@ -2,7 +2,7 @@ ## files generated by popular Visual Studio add-ons. # Azure Functions localsettings file -local.settings.json +# local.settings.json # User-specific files *.suo diff --git a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/getSecret.cs b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/getSecret.cs index 2f1da1fd..cca3e7a9 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/getSecret.cs +++ b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/getSecret.cs @@ -7,10 +7,9 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Microsoft.Azure.Services.AppAuthentication; -using Microsoft.Azure.KeyVault; using Microsoft.Extensions.Configuration; - +using Azure.Security.KeyVault.Secrets; +using Azure.Identity; namespace Company.Function { @@ -34,13 +33,12 @@ public static async Task Run( .Build(); var kvName = config["KeyVaultName"]; - var kvUri = $"https://{kvName}.vault.azure.net/"; - log.LogInformation($"Obtaining secret {secret} from {kvUri}"); + log.LogInformation($"Obtaining secret {secret} from {kvName}"); - var serviceTokenProvider = new AzureServiceTokenProvider(); - var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(serviceTokenProvider.KeyVaultTokenCallback)); - dbconstring = (keyVaultClient.GetSecretAsync(kvUri, secret).Result).Value; + var client = new SecretClient(new Uri($"https://{kvName}.vault.azure.net/"), new DefaultAzureCredential()); + var response = await client.GetSecretAsync("conSQLite"); + dbconstring = response.Value.Value; } string responseMessage = string.IsNullOrEmpty(secret) diff --git a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/local.settings.json b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/local.settings.json new file mode 100644 index 00000000..d19ff96d --- /dev/null +++ b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/local.settings.json @@ -0,0 +1,7 @@ +{ + "IsEncrypted": false, + "Values": { + "FUNCTIONS_WORKER_RUNTIME": "dotnet", + "KeyVaultName": "foodvault-dev" + } +} \ No newline at end of file diff --git a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/mi-func.csproj b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/mi-func.csproj index dbd922c6..eefca7bc 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/mi-func.csproj +++ b/demos/07-secure-solutions/02-managed-identity/demo-03/mi-func/mi-func.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/.vscode/launch.json b/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/.vscode/launch.json deleted file mode 100644 index 7dd37eac..00000000 --- a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/.vscode/launch.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ - { - "name": ".NET Core Launch (console)", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/bin/Debug/net6.0/AppConfigConsole.dll", - "args": [], - "cwd": "${workspaceFolder}", - // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console - "console": "internalConsole", - "stopAtEntry": false - }, - { - "name": ".NET Core Attach", - "type": "coreclr", - "request": "attach", - "processId": "${command:pickProcess}" - } - ] -} diff --git a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/AppConfigConsole.csproj b/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/AppConfigConsole.csproj deleted file mode 100644 index 451016d4..00000000 --- a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/AppConfigConsole.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - Exe - net6.0 - - - - - - \ No newline at end of file diff --git a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/Program.cs b/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/Program.cs deleted file mode 100644 index 7b4b34c7..00000000 --- a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/Program.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Azure.Identity; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Configuration.AzureAppConfiguration; - -namespace AppConfigConsole -{ - class Program - { - static void Main(string[] args) - { - var builder = new ConfigurationBuilder(); - - // Update Connection String - var cs = ""; - builder.AddAzureAppConfiguration(options => - { - options.Connect(cs) - // Uncomment if you want to use a specific label - .Select(KeyFilter.Any, "prod") - .ConfigureKeyVault(kv => - { - kv.SetCredential(new DefaultAzureCredential()); - }); - }); - - var config = builder.Build(); - Console.WriteLine(config["Settings:Title"] ?? "No Title received"); - Console.WriteLine(config["Settings:ConnectionString"] ?? "No ConString received"); - } - } -} diff --git a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/appsettings.json b/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/appsettings.json deleted file mode 100644 index e69de29b..00000000 diff --git a/demos/07-secure-solutions/03-app-config/_images/app-config-con-string.png b/demos/07-secure-solutions/03-app-config/demo-01/_images/app-config-con-string.png similarity index 100% rename from demos/07-secure-solutions/03-app-config/_images/app-config-con-string.png rename to demos/07-secure-solutions/03-app-config/demo-01/_images/app-config-con-string.png diff --git a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.azure/config b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.azure/config similarity index 60% rename from demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.azure/config rename to demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.azure/config index 9dada5fb..93ab059c 100644 --- a/demos/07-secure-solutions/02-managed-identity/demo-01/food-api-mi/.azure/config +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.azure/config @@ -1,7 +1,7 @@ [defaults] group = az204-m07-secure-solutions-dev sku = FREE -appserviceplan = foodplan-dev +appserviceplan = config-plan-dev location = westeurope -web = foodapi-dev +web = config-api-dev diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.vscode/launch.json b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.vscode/launch.json new file mode 100644 index 00000000..dc331253 --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (web)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug/net6.0/config-service-api.dll", + "args": [], + "cwd": "${workspaceFolder}", + "stopAtEntry": false, + "serverReadyAction": { + "action": "openExternally", + "pattern": "\\bNow listening on:\\s+(https?://\\S+)" + }, + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/.vscode/tasks.json b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.vscode/tasks.json similarity index 76% rename from demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/.vscode/tasks.json rename to demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.vscode/tasks.json index 8aaeefda..73211433 100644 --- a/demos/07-secure-solutions/03-app-config/demo-01/AppConfigConsole/.vscode/tasks.json +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/.vscode/tasks.json @@ -7,7 +7,7 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/AppConfigConsole.csproj", + "${workspaceFolder}/config-service-api.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -19,7 +19,7 @@ "type": "process", "args": [ "publish", - "${workspaceFolder}/AppConfigConsole.csproj", + "${workspaceFolder}/config-service-api.csproj", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], @@ -32,9 +32,8 @@ "args": [ "watch", "run", - "${workspaceFolder}/AppConfigConsole.csproj", - "/property:GenerateFullPaths=true", - "/consoleloggerparameters:NoSummary" + "--project", + "${workspaceFolder}/config-service-api.csproj" ], "problemMatcher": "$msCompile" } diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Config/AppConfig.cs b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Config/AppConfig.cs new file mode 100644 index 00000000..1da0d2a1 --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Config/AppConfig.cs @@ -0,0 +1,36 @@ +public class AppSettings +{ + public string Title { get; set; } + public bool AuthEnabled { get; set; } + public string DBConnectionString { get; set; } + public string KeyVault { get; set; } + public string AppConfigEndpoint { get; set; } + public string AppConfigConnection { get; set; } + public string Sentinel { get; set; } + public string Environment { get; set; } +} + +public class FeatureManagement +{ + public bool PremiumFeature { get; set; } +} + +public class Logging +{ + public LogLevel LogLevel { get; set; } +} + +public class LogLevel +{ + public string Default { get; set; } + public string Microsoft { get; set; } + public string MicrosoftHostingLifetime { get; set; } +} + +public class AppConfig +{ + public Logging Logging { get; set; } + public string AllowedHosts { get; set; } + public AppSettings Settings { get; set; } + public FeatureManagement FeatureManagement { get; set; } +} \ No newline at end of file diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Controllers/ConfigController.cs b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Controllers/ConfigController.cs new file mode 100644 index 00000000..0d15fbc3 --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Controllers/ConfigController.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using Azure.Security.KeyVault.Secrets; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace config_service_api.Controllers; + +[ApiController] +[Route("[controller]")] +public class ConfigController : ControllerBase +{ + IConfiguration cfg; + SecretClient sc; + + private readonly ILogger logger; + + public ConfigController(ILogger ilogger, IConfiguration config, SecretClient secretClient) + { + cfg = config; + logger = ilogger; + sc = secretClient; + } + + [HttpGet(Name = "GetConfig")] + public ActionResult Get() + { + var config = cfg.Get(); + return Ok(config); + } + + [HttpGet("GetPremiumFeatureEnabled")] + public ActionResult GetPremium() + { + //get string typed config + var config = cfg.Get(); + return Ok(config); + } + + [HttpGet("GetSecretFromVault")] + public async Task GetSecretFromVault() + { + var response = await sc.GetSecretAsync("conSQLite"); + return response.Value.Value; + } +} diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Program.cs b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Program.cs new file mode 100644 index 00000000..28aa92b4 --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Program.cs @@ -0,0 +1,75 @@ +using System; +using Azure.Identity; +using Azure.Security.KeyVault.Secrets; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.OpenApi.Models; + +var builder = WebApplication.CreateBuilder(args); + +// Access Base Configuration +IConfiguration Configuration = builder.Configuration; +builder.Services.AddSingleton(Configuration); +var cfg = Configuration.Get(); + +builder.Configuration.AddAzureAppConfiguration(options => +{ + options.Connect(cfg.Settings.AppConfigConnection) + .ConfigureKeyVault(kv => + { + kv.SetCredential(new DefaultAzureCredential()); + }) + .Select("*", cfg.Settings.Environment) + .ConfigureRefresh(refreshOptions => + refreshOptions.Register("Settings:Sentinel", refreshAll: true)); +}); + +// Add services to the container. +// Key Vault Client +var client = new SecretClient(new Uri($"https://{cfg.Settings.KeyVault}"), new DefaultAzureCredential()); +builder.Services.AddSingleton(client); + +builder.Services.AddControllers(); + +// Swagger +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(c => +{ + c.SwaggerDoc("v1", new OpenApiInfo { Title = "App-Config-Api", Version = "v1" }); +}); + +// Cors +builder.Services.AddCors(o => o.AddPolicy("nocors", builder => +{ + builder + .SetIsOriginAllowed(host => true) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); +})); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} + +// Swagger +app.UseSwagger(); +app.UseSwaggerUI(c => +{ + c.SwaggerEndpoint("/swagger/v1/swagger.json", "App-Config-Service-Api"); + c.RoutePrefix = string.Empty; +}); + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Properties/launchSettings.json b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Properties/launchSettings.json new file mode 100644 index 00000000..75120118 --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:33908", + "sslPort": 44365 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "", + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "", + "applicationUrl": "https://localhost:5001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/appsettings.json b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/appsettings.json new file mode 100644 index 00000000..b1d414af --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/appsettings.json @@ -0,0 +1,23 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*", + "Settings": { + "Title": "App Config From File", + "AuthEnabled": false, + "DBConnectionString": "Data Source=./food-local.db", + "KeyVault": "foodvault-dev.vault.azure.net", + "AppConfigEndpoint": "https://foodconfig-dev.azconfig.io", + "AppConfigConnection": "Endpoint=https://foodconfig-dev.azconfig.io;Id=fVrb-l9-s0:Kn9pxn7Ueh+XZ9viVGsR;Secret=hbr+jKb0SgK+RIrud2EXWXKZkschTJt23bCzN29xWRI=", + "Sentinel": 1, + "Environment": "production" + }, + "FeatureManagement": { + "PremiumFeature": false + } +} diff --git a/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/config-service-api.csproj b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/config-service-api.csproj new file mode 100644 index 00000000..17018f58 --- /dev/null +++ b/demos/07-secure-solutions/03-app-config/demo-01/config-service-api/config-service-api.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + config_service_api + + + + + + + + + + + + diff --git a/demos/07-secure-solutions/03-app-config/demo-01/create-app-conf.azcli b/demos/07-secure-solutions/03-app-config/demo-01/create-app-conf.azcli index 24ca83d5..67da7136 100644 --- a/demos/07-secure-solutions/03-app-config/demo-01/create-app-conf.azcli +++ b/demos/07-secure-solutions/03-app-config/demo-01/create-app-conf.azcli @@ -1,29 +1,50 @@ -rnd=dev -grp=az204-m07-secure-solutions-$rnd +env=dev +grp=az204-m07-secure-solutions-$env loc=westeurope -cfg=foodconfig-$rnd -vault=foodvault-$rnd +cfg=foodconfig-$env +vault=foodvault-$env +app=config-api-$env +plan=config-plan-$env # create appconfig and add a value -az appconfig create -g $grp -n $cfg -l $loc --sku free -az appconfig kv set -n foodconfig-$rnd --key "Settings:Title" --value "Fancy Food App Dev" -y -az appconfig kv set -n foodconfig-$rnd --key "Settings:Title" --value "Fancy Food App Staging" -y --label staging -az appconfig kv set -n foodconfig-$rnd --key "Settings:Title" --value "Fancy Food App" -y --label prod +appconfigid=$(az appconfig create -g $grp -n $cfg -l $loc --sku free --query id -o tsv) +az appconfig kv set -n $cfg --key "Settings:Title" --value "App Config Demo Dev" -y +az appconfig kv set -n $cfg --key "Settings:Title" --value "App Config Demo" -y --label production +az appconfig kv set -n $cfg --key "Settings:Sentinel" --value 1 -y +az appconfig kv set -n $cfg --key "Settings:Sentinel" --value 1 -y --label production -# key-vault binding +# app config key-vault binding cfgmi=$(az appconfig identity assign -g $grp -n $cfg --query principalId -o tsv) az keyvault set-policy -n $vault --object-id $cfgmi --secret-permissions get list -az appconfig kv set-keyvault -n $cfg --key "Settings:ConnectionString" --secret-identifier "https://$vault.vault.azure.net/Secrets/conSQLite" -y -az appconfig kv set-keyvault -n $cfg --key "Settings:ConnectionString" --secret-identifier "https://$vault.vault.azure.net/Secrets/conSQLServer" -y --label prod +az appconfig kv set-keyvault -n $cfg --key "Settings:DBConnectionString" --secret-identifier "https://$vault.vault.azure.net/Secrets/conSQLite" -y +az appconfig kv set-keyvault -n $cfg --key "Settings:DBConnectionString" --secret-identifier "https://$vault.vault.azure.net/Secrets/conSQLServer" -y --label production # alternative: keyvault policy assignment using service principal # principal=http://foodprincipal # az ad sp create-for-rbac -n $principal --sdk-auth # az keyvault set-policy -n $vault --spn $principal --secret-permissions get list -# create a feature flag and turn it on +# create hosting webapp and add keyvault permissions to managed identity +cd config-service-api +az webapp up -n $app -g $grp -p $plan -l $loc --sku Free --runtime "DOTNET|6.0" +cd .. +webmi=$(az webapp identity assign -g $grp -n $app --query principalId -o tsv) +az keyvault set-policy -n $vault --object-id $webmi --secret-permissions get list + +sleep 15 # wait for managed identity to propagate + +# add app config reader permissions to managed identity and add the endpoint to webapp config +az role assignment create --role "App Configuration Data Reader" --assignee $webmi --scope $appconfigid +configEP=$(az appconfig list -g $grp --query "[?name=='$cfg'].endpoint" -o tsv) +configCon=$(az appconfig credential list --name $cfg --query [0].connectionString -o tsv) +az webapp config appsettings set -g $grp -n $app --settings "Settings:AppConfigEndpoint=$configEP" +az webapp config appsettings set -g $grp -n $app --settings "Settings:AppConfigConnection=$configCon" +az webapp restart -g $grp -n $app + +# create a feature flag and turn it on az appconfig feature set -n $cfg --feature PremiumFeature -y -az appconfig feature enable -n $cfg --feature PremiumFeature -y +az appconfig feature set -n $cfg --feature PremiumFeature -y --label production +az appconfig feature enable -n $cfg --feature PremiumFeature -y \ No newline at end of file diff --git a/demos/07-secure-solutions/03-app-config/demo-01/readme.md b/demos/07-secure-solutions/03-app-config/demo-01/readme.md index dfc71243..cac0a2d8 100644 --- a/demos/07-secure-solutions/03-app-config/demo-01/readme.md +++ b/demos/07-secure-solutions/03-app-config/demo-01/readme.md @@ -1,13 +1,5 @@ -# Demo +# App Configuration Services -Execute `create-app-conf.azcli` to create required base services. +- Execute `create-app-conf.azcli` to create required base services. -Get the Connection String of the AppConfig Service and add it as env var: - -```powershell -setx AppConfigCS "Endpoint=https://foodconfig-20433.azconfig.io;Id=YhpI-l9-s0:bXPh6ApX2WzFki7odj33;Secret=o8LoLhCIy5Rn3okemD0CkDan4y83rozMR7C8cRz/SECRET=" -``` - -![secret](_images/app-config-con-string.png) - -Examine Demo-01 and execute it using `dotnet run` \ No newline at end of file + >Note: This demo assumes that you have already created the base services from 01-key-vault by executing `create-vault.azcli` \ No newline at end of file diff --git a/tooling/04-cli/readme.md b/tooling/04-cli/readme.md index 5c460d12..1c24e83c 100644 --- a/tooling/04-cli/readme.md +++ b/tooling/04-cli/readme.md @@ -65,6 +65,12 @@ az extension list-available --output table az extension add --name ``` +Set Azrue CLI to auto-update: + +```bash +az config set extension.use_dynamic_install=yes_without_prompt +``` + ### List and set Subscriptions List Subscriptions: