From e8ddcee76fa29a5bbe6d713865ba68a2ee23f422 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Thu, 27 Feb 2025 10:47:49 +0100 Subject: [PATCH 01/17] Dashboard --- .dockerignore | 30 +++++ Altinn.Correspondence.sln | 9 ++ .../Altinn.Correspondence.Dashboard.csproj | 25 ++++ .../Dockerfile | 29 +++++ .../HangfireDashboardAuthorizationFilter.cs | 11 ++ .../Program.cs | 28 ++++ .../Properties/launchSettings.json | 52 ++++++++ .../Altinn.Correspondence.Dashboard/app.http | 2 + .../appsettings.Development.json | 11 ++ .../appsettings.json | 9 ++ .../deploy-dashboard.sh | 120 ++++++++++++++++++ 11 files changed, 326 insertions(+) create mode 100644 .dockerignore create mode 100644 tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj create mode 100644 tools/Altinn.Correspondence.Dashboard/Dockerfile create mode 100644 tools/Altinn.Correspondence.Dashboard/HangfireDashboardAuthorizationFilter.cs create mode 100644 tools/Altinn.Correspondence.Dashboard/Program.cs create mode 100644 tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json create mode 100644 tools/Altinn.Correspondence.Dashboard/app.http create mode 100644 tools/Altinn.Correspondence.Dashboard/appsettings.Development.json create mode 100644 tools/Altinn.Correspondence.Dashboard/appsettings.json create mode 100644 tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..fe1152bdb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/Altinn.Correspondence.sln b/Altinn.Correspondence.sln index d9e3ca576..f8b7614cf 100644 --- a/Altinn.Correspondence.sln +++ b/Altinn.Correspondence.sln @@ -21,6 +21,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Altinn.Correspondence.Commo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Altinn.Correspondence.LoadTests.DatabasePopulater", "Test\Altinn.Correspondence.LoadTests.DatabasePopulater\Altinn.Correspondence.LoadTests.DatabasePopulater.csproj", "{3E5EEBF3-366E-48F8-9D57-1975F95D4FAD}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{C20EA94C-2635-4683-8EF4-E98C6EBF811F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Altinn.Correspondence.Dashboard", "tools\Altinn.Correspondence.Dashboard\Altinn.Correspondence.Dashboard.csproj", "{11558171-1B06-40A8-A230-3E136B9F187A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -59,6 +63,10 @@ Global {3E5EEBF3-366E-48F8-9D57-1975F95D4FAD}.Debug|Any CPU.Build.0 = Debug|Any CPU {3E5EEBF3-366E-48F8-9D57-1975F95D4FAD}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E5EEBF3-366E-48F8-9D57-1975F95D4FAD}.Release|Any CPU.Build.0 = Release|Any CPU + {11558171-1B06-40A8-A230-3E136B9F187A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {11558171-1B06-40A8-A230-3E136B9F187A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {11558171-1B06-40A8-A230-3E136B9F187A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {11558171-1B06-40A8-A230-3E136B9F187A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -66,6 +74,7 @@ Global GlobalSection(NestedProjects) = preSolution {D78A36B1-D457-4FF7-B01E-82A0C3C64EDC} = {DC791FEF-108F-4773-8B84-56986CB90767} {3E5EEBF3-366E-48F8-9D57-1975F95D4FAD} = {DC791FEF-108F-4773-8B84-56986CB90767} + {11558171-1B06-40A8-A230-3E136B9F187A} = {C20EA94C-2635-4683-8EF4-E98C6EBF811F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3508DF12-D3DE-4956-ABAB-31D7321B72C7} diff --git a/tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj b/tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj new file mode 100644 index 000000000..5955bf08b --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj @@ -0,0 +1,25 @@ + + + + net9.0 + enable + enable + db15b22b-b1d8-435c-962f-0c7350056033 + Linux + ..\.. + + + + + + + + + + + + + + + + diff --git a/tools/Altinn.Correspondence.Dashboard/Dockerfile b/tools/Altinn.Correspondence.Dashboard/Dockerfile new file mode 100644 index 000000000..9deb5a472 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/Dockerfile @@ -0,0 +1,29 @@ +# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +# This stage is used when running from VS in fast mode (Default for Debug configuration) +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base +USER $APP_UID +WORKDIR /app +EXPOSE 80 +EXPOSE 81 + +# This stage is used to build the service project +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj", "tools/Altinn.Correspondence.Dashboard/"] +RUN dotnet restore "tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj" +COPY . . +WORKDIR "/src/tools/Altinn.Correspondence.Dashboard" +RUN dotnet build "./Altinn.Correspondence.Dashboard.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# This stage is used to publish the service project to be copied to the final stage +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Altinn.Correspondence.Dashboard.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false3 + +# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Altinn.Correspondence.Dashboard.dll"] \ No newline at end of file diff --git a/tools/Altinn.Correspondence.Dashboard/HangfireDashboardAuthorizationFilter.cs b/tools/Altinn.Correspondence.Dashboard/HangfireDashboardAuthorizationFilter.cs new file mode 100644 index 000000000..ec6c410d4 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/HangfireDashboardAuthorizationFilter.cs @@ -0,0 +1,11 @@ +using Hangfire.Annotations; +using Hangfire.Dashboard; + +internal class HangfireDashboardAuthorizationFilter : IDashboardAuthorizationFilter +{ + // Dummy implementation. Handled by Container App. + public bool Authorize([NotNull] DashboardContext context) + { + return true; + } +} \ No newline at end of file diff --git a/tools/Altinn.Correspondence.Dashboard/Program.cs b/tools/Altinn.Correspondence.Dashboard/Program.cs new file mode 100644 index 000000000..1edbac3c2 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/Program.cs @@ -0,0 +1,28 @@ +using Altinn.Correspondence.Integrations.Hangfire; +using Altinn.Correspondence.Persistence; +using Hangfire; +using Microsoft.ApplicationInsights.AspNetCore.Extensions; + +var builder = WebApplication.CreateBuilder(args); +builder.Configuration + .AddJsonFile("appsettings.json", true, true) + .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true, true) + .AddJsonFile("appsettings.local.json", true, true); +builder.Services.AddPersistence(builder.Configuration); +builder.Services.AddApplicationInsightsTelemetry(new ApplicationInsightsServiceOptions() +{ + EnableAdaptiveSampling = false +}); +builder.Services.ConfigureHangfire(); + +var app = builder.Build(); + +app.UseHttpsRedirection(); + +app.UseHangfireDashboard("/hangfire", new DashboardOptions() +{ + Authorization = [new HangfireDashboardAuthorizationFilter()] +}); +app.MapGet("/", () => Results.Redirect("/hangfire")); + +app.Run(); \ No newline at end of file diff --git a/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json b/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json new file mode 100644 index 000000000..69389a5c2 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json @@ -0,0 +1,52 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5097" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7224;http://localhost:5097" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/", + "environmentVariables": { + "ASPNETCORE_HTTPS_PORTS": "80", + "ASPNETCORE_HTTP_PORTS": "81" + }, + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:44756", + "sslPort": 44305 + } + } +} \ No newline at end of file diff --git a/tools/Altinn.Correspondence.Dashboard/app.http b/tools/Altinn.Correspondence.Dashboard/app.http new file mode 100644 index 000000000..037c82862 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/app.http @@ -0,0 +1,2 @@ +# For more info on HTTP files go to https://aka.ms/vs/httpfile +GET https://localhost:7220/weatherforecast \ No newline at end of file diff --git a/tools/Altinn.Correspondence.Dashboard/appsettings.Development.json b/tools/Altinn.Correspondence.Dashboard/appsettings.Development.json new file mode 100644 index 000000000..ef0ea24b5 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "DatabaseOptions": { + "ConnectionString": "Host=host.docker.internal:5432;Username=postgres;Password=postgres;Database=correspondence;Pooling=true;Maximum Pool Size=20;Minimum Pool Size=0;" + } +} diff --git a/tools/Altinn.Correspondence.Dashboard/appsettings.json b/tools/Altinn.Correspondence.Dashboard/appsettings.json new file mode 100644 index 000000000..10f68b8c8 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh b/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh new file mode 100644 index 000000000..3fb57ad75 --- /dev/null +++ b/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +# Pre-requisites +# Install gh (sudo apt install gh) +# Install az tools (sudo apt install az), and run az login then select the correct subscription + +# Script to deploy Hangfire container app. +# This script will create a new App Registration and Service Principal, and deploy the Dashboard container app. +# It will also configure authentication for the container app. +# This was otherwise not possible to do using bicep as we usually would, hence the script as it will run as a user who can make service principals + +# Exit on error +set -e + +# Default values +ENVIRONMENT_NAME="" + +# Function to display usage +usage() { + echo "Usage: $0 -e " + echo "Example: $0 -e test" + exit 1 +} + +# Parse command line arguments +while getopts "e:i:" opt; do + case $opt in + e) ENVIRONMENT_NAME="$OPTARG";; + ?) usage;; + esac +done + +# Validate required parameters +if [ -z "$ENVIRONMENT_NAME" ]; then + echo "Error: Missing required parameters" + usage +fi + +# Get the latest git tag +GIT_TAG=$(git describe --tags --abbrev=0) +if [ -z "$GIT_TAG" ]; then + echo "Error: No git tag found" + exit 1 +fi + +# Set constants +LOCATION="Norway East" +APP_NAME="altinn-corr-${ENVIRONMENT_NAME}-dashboard-app" +RESOURCE_GROUP="altinn-corr-${ENVIRONMENT_NAME}-rg" +DOCKER_IMAGE_NAME="ghcr.io/altinn/altinn-correspondence-dashboard:${GIT_TAG}" + +echo "Building and pushing Hangfire Dashboard container..." +echo "Building Docker image..." +docker build -t $DOCKER_IMAGE_NAME -f Dockerfile ../.. + +# Login to GitHub packages +echo "Logging in to GitHub packages..." +gh auth login -w -s write:packages +gh auth setup-git +echo "Our username" +echo $(gh api user --jq '.login') +echo "Our password" +echo $(gh auth token) + +docker login ghcr.io -u $(gh api user --jq '.login') -p $(gh auth token) + +# Push the image +echo "Pushing image to GitHub packages..." +docker push $DOCKER_IMAGE_NAME + +# Set the image parameter to the newly built image + +echo "Creating Container App with authentication..." +echo "Using Resource Group: $RESOURCE_GROUP" +echo "Location: $LOCATION" +echo "App Name: $APP_NAME" + +# Create the App Registration +echo "Creating App Registration..." +APP_ID=$(az ad app create --display-name "$APP_NAME" --query appId --output tsv) +echo "App Registration created with ID: $APP_ID" + +# Create service principal for the app +echo "Creating Service Principal..." +az ad sp create --id $APP_ID + +# Generate a secret for the app registration +echo "Generating client secret..." +CLIENT_SECRET=$(az ad app credential reset --id $APP_ID --query password --output tsv) + +# Create Container Apps Environment if it doesn't exist +echo "Creating Container Apps Environment..." +az containerapp env create \ + --name "$ENVIRONMENT_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --location "$LOCATION" + +# Create the Container App +echo "Creating Container App..." +az containerapp create \ + --name "$APP_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --environment "$ENVIRONMENT_NAME" \ + --image "$DOCKER_IMAGE_NAME" \ + --target-port 80 \ + --ingress external + +# Configure authentication +echo "Configuring authentication..." +az containerapp auth microsoft update \ + --name "$APP_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --client-id "$APP_ID" \ + --client-secret "$CLIENT_SECRET" \ + --allowed-audiences "api://$APP_ID" + +echo "Container App deployment complete!" +echo "App Registration ID: $APP_ID" +echo "Please save these credentials securely." + From 78c4e8d97017b7292377d5bf659f5a97e5530f63 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Thu, 27 Feb 2025 10:48:02 +0100 Subject: [PATCH 02/17] This leads to double messages --- .../Hangfire/DependencyInjection.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs b/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs index 613c25dd1..d50223e92 100644 --- a/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs +++ b/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs @@ -1,11 +1,8 @@ -using Altinn.Correspondence.Integrations.Slack; -using Hangfire; +using Hangfire; using Hangfire.PostgreSql; using Microsoft.ApplicationInsights; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Serilog.Core; namespace Altinn.Correspondence.Integrations.Hangfire; public static class DependencyInjection @@ -21,11 +18,6 @@ public static void ConfigureHangfire(this IServiceCollection services) config.UseSerilogLogProvider(); config.UseFilter(new HangfireAppRequestFilter(provider.GetRequiredService())); config.UseSerializerSettings(new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); - config.UseFilter( - new SlackExceptionHandler( - provider.GetRequiredService(), - provider.GetRequiredService>()) - ); }); services.AddHangfireServer(options => options.SchedulePollingInterval = TimeSpan.FromSeconds(2)); } From d8943a58272e579f250017a74b81561910c6718a Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Thu, 27 Feb 2025 10:55:24 +0100 Subject: [PATCH 03/17] Restored old functionality, simplified ours instead --- .../Hangfire/DependencyInjection.cs | 11 +++++++++-- tools/Altinn.Correspondence.Dashboard/Program.cs | 10 +++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs b/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs index d50223e92..b483ac6ac 100644 --- a/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs +++ b/src/Altinn.Correspondence.Integrations/Hangfire/DependencyInjection.cs @@ -1,7 +1,9 @@ -using Hangfire; +using Altinn.Correspondence.Integrations.Slack; +using Hangfire; using Hangfire.PostgreSql; using Microsoft.ApplicationInsights; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace Altinn.Correspondence.Integrations.Hangfire; @@ -18,7 +20,12 @@ public static void ConfigureHangfire(this IServiceCollection services) config.UseSerilogLogProvider(); config.UseFilter(new HangfireAppRequestFilter(provider.GetRequiredService())); config.UseSerializerSettings(new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); - }); + config.UseFilter( + new SlackExceptionHandler( + provider.GetRequiredService(), + provider.GetRequiredService>()) + ); + }); services.AddHangfireServer(options => options.SchedulePollingInterval = TimeSpan.FromSeconds(2)); } } diff --git a/tools/Altinn.Correspondence.Dashboard/Program.cs b/tools/Altinn.Correspondence.Dashboard/Program.cs index 1edbac3c2..08819e976 100644 --- a/tools/Altinn.Correspondence.Dashboard/Program.cs +++ b/tools/Altinn.Correspondence.Dashboard/Program.cs @@ -1,6 +1,7 @@ using Altinn.Correspondence.Integrations.Hangfire; using Altinn.Correspondence.Persistence; using Hangfire; +using Hangfire.PostgreSql; using Microsoft.ApplicationInsights.AspNetCore.Extensions; var builder = WebApplication.CreateBuilder(args); @@ -13,7 +14,14 @@ { EnableAdaptiveSampling = false }); -builder.Services.ConfigureHangfire(); +builder.Services.AddSingleton(); +builder.Services.AddHangfire((provider, config) => + { + config.UsePostgreSqlStorage( + c => c.UseConnectionFactory(provider.GetService()) + ); + config.UseSerilogLogProvider(); +}); var app = builder.Build(); From 35190ace3d726e96f3a48030cf2dcc9b9bd2be69 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Thu, 27 Feb 2025 12:02:08 +0100 Subject: [PATCH 04/17] Got no swagger --- .../Properties/launchSettings.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json b/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json index 69389a5c2..515aca614 100644 --- a/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json +++ b/tools/Altinn.Correspondence.Dashboard/Properties/launchSettings.json @@ -3,7 +3,6 @@ "http": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, @@ -13,7 +12,6 @@ "https": { "commandName": "Project", "launchBrowser": true, - "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, @@ -23,7 +21,6 @@ "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, - "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } From 196899f407d399ac8a09c8ce30b1c46a4ffcb101 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Thu, 27 Feb 2025 12:02:25 +0100 Subject: [PATCH 05/17] Fixed deploy script --- .../deploy-dashboard.sh | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh b/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh index 3fb57ad75..37682b312 100644 --- a/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh +++ b/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh @@ -60,9 +60,9 @@ gh auth setup-git echo "Our username" echo $(gh api user --jq '.login') echo "Our password" -echo $(gh auth token) +#echo $(gh auth status -t 2>&1 | grep Token | cut -d':' -f2 | xargs) -docker login ghcr.io -u $(gh api user --jq '.login') -p $(gh auth token) +docker login ghcr.io -u $(gh api user --jq '.login') -p $(gh auth status -t 2>&1 | grep Token | cut -d':' -f2 | xargs) # Push the image echo "Pushing image to GitHub packages..." @@ -88,30 +88,25 @@ az ad sp create --id $APP_ID echo "Generating client secret..." CLIENT_SECRET=$(az ad app credential reset --id $APP_ID --query password --output tsv) -# Create Container Apps Environment if it doesn't exist -echo "Creating Container Apps Environment..." -az containerapp env create \ - --name "$ENVIRONMENT_NAME" \ - --resource-group "$RESOURCE_GROUP" \ - --location "$LOCATION" - # Create the Container App echo "Creating Container App..." az containerapp create \ --name "$APP_NAME" \ --resource-group "$RESOURCE_GROUP" \ - --environment "$ENVIRONMENT_NAME" \ + --environment "altinn-corr-$ENVIRONMENT_NAME-env" \ --image "$DOCKER_IMAGE_NAME" \ --target-port 80 \ --ingress external # Configure authentication echo "Configuring authentication..." +TENANT_ID=${az account show --query tenantId -o tsv} az containerapp auth microsoft update \ --name "$APP_NAME" \ --resource-group "$RESOURCE_GROUP" \ --client-id "$APP_ID" \ --client-secret "$CLIENT_SECRET" \ + --tenant-id "$TENANT_ID" \ --allowed-audiences "api://$APP_ID" echo "Container App deployment complete!" From 2e11ab93157d248f33afa002f33287f71f37f794 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Fri, 28 Feb 2025 11:31:14 +0100 Subject: [PATCH 06/17] Fix dockerfile --- tools/Altinn.Correspondence.Dashboard/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Altinn.Correspondence.Dashboard/Dockerfile b/tools/Altinn.Correspondence.Dashboard/Dockerfile index 9deb5a472..de5fe0459 100644 --- a/tools/Altinn.Correspondence.Dashboard/Dockerfile +++ b/tools/Altinn.Correspondence.Dashboard/Dockerfile @@ -5,7 +5,7 @@ FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base USER $APP_UID WORKDIR /app EXPOSE 80 -EXPOSE 81 +ENV ASPNETCORE_URLS=http://+:80 # This stage is used to build the service project FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build From 803ad826200198682c4a827461c409dd36907dfe Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Fri, 28 Feb 2025 11:57:07 +0100 Subject: [PATCH 07/17] Use port 2526 for dashboard --- tools/Altinn.Correspondence.Dashboard/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Altinn.Correspondence.Dashboard/Dockerfile b/tools/Altinn.Correspondence.Dashboard/Dockerfile index de5fe0459..7c821b79e 100644 --- a/tools/Altinn.Correspondence.Dashboard/Dockerfile +++ b/tools/Altinn.Correspondence.Dashboard/Dockerfile @@ -4,8 +4,8 @@ FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base USER $APP_UID WORKDIR /app -EXPOSE 80 -ENV ASPNETCORE_URLS=http://+:80 +EXPOSE 2526 +ENV ASPNETCORE_URLS=http://+:2526 # This stage is used to build the service project FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build From 187a567ba0fe9416745e140db3cb4ddddfe1b532 Mon Sep 17 00:00:00 2001 From: Ceredron <36594318+Ceredron@users.noreply.github.com> Date: Sat, 1 Mar 2025 17:40:22 +0100 Subject: [PATCH 08/17] Github action and biceps --- .azure/applications/dashboard.bicep | 26 ++++++++ .azure/modules/containerApp/dashboard.bicep | 37 ++++++++++++ .github/workflows/deploy-dashboard.yml | 66 +++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 .azure/applications/dashboard.bicep create mode 100644 .azure/modules/containerApp/dashboard.bicep create mode 100644 .github/workflows/deploy-dashboard.yml diff --git a/.azure/applications/dashboard.bicep b/.azure/applications/dashboard.bicep new file mode 100644 index 000000000..911391cc1 --- /dev/null +++ b/.azure/applications/dashboard.bicep @@ -0,0 +1,26 @@ +param location string +param environment string +param containerAppEnvironmentName string +param containerImage string +param minReplicas int = 1 +param maxReplicas int = 1 + +module containerApp '../modules/containerApp/dashboard.bicep' = { + name: 'dashboard' + params: { + name: 'altinn-corr-${environment}-dashboard' + location: location + environmentName: containerAppEnvironmentName + containerImage: containerImage + minReplicas: minReplicas + maxReplicas: maxReplicas + env: [ + { + name: 'ASPNETCORE_ENVIRONMENT' + value: environment + } + ] + } +} + +output dashboardUrl string = containerApp.outputs.url diff --git a/.azure/modules/containerApp/dashboard.bicep b/.azure/modules/containerApp/dashboard.bicep new file mode 100644 index 000000000..23a8e01a7 --- /dev/null +++ b/.azure/modules/containerApp/dashboard.bicep @@ -0,0 +1,37 @@ +param location string +param name string +param environmentName string +param containerImage string +param minReplicas int = 1 +param maxReplicas int = 1 +param env array = [] + +resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { + name: name + location: location + properties: { + environmentId: environmentName + configuration: { + ingress: { + external: true + targetPort: 2526 + allowInsecure: false + } + } + template: { + containers: [ + { + name: 'dashboard' + image: containerImage + env: env + } + ] + scale: { + minReplicas: minReplicas + maxReplicas: maxReplicas + } + } + } +} + +output url string = containerApp.properties.configuration.ingress.fqdn diff --git a/.github/workflows/deploy-dashboard.yml b/.github/workflows/deploy-dashboard.yml new file mode 100644 index 000000000..e03aa8595 --- /dev/null +++ b/.github/workflows/deploy-dashboard.yml @@ -0,0 +1,66 @@ +name: Deploy Dashboard + +on: + workflow_dispatch: + inputs: + environment: + type: choice + description: "Environment to deploy to" + options: + - test + - staging + - production + - yt01 + - at21 + - at22 + - at23 + - at24 + +permissions: + id-token: write + contents: read + packages: write + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + environment: ${{ github.event.inputs.environment }} + + steps: + - uses: actions/checkout@v4 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + file: tools/Altinn.Correspondence.Dashboard/Dockerfile + push: true + tags: | + ghcr.io/altinn/altinn-correspondence-dashboard:${{ github.sha }} + ghcr.io/altinn/altinn-correspondence-dashboard:latest + + - name: Azure Login + uses: azure/login@v1 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Deploy Bicep + uses: azure/arm-deploy@v1 + with: + scope: resourcegroup + resourceGroupName: ${{ secrets.RESOURCE_GROUP }} + template: .azure/applications/dashboard.bicep + parameters: > + location=${{ secrets.LOCATION }} + environment=${{ github.event.inputs.environment }} + containerAppEnvironmentName=${{ secrets.CONTAINER_APP_ENVIRONMENT }} + containerImage=ghcr.io/altinn/altinn-correspondence-dashboard:${{ github.sha }} From d1e8a58e099b0acf864951bb5ca020a7eebcc9b4 Mon Sep 17 00:00:00 2001 From: Ceredron <36594318+Ceredron@users.noreply.github.com> Date: Sat, 1 Mar 2025 18:53:14 +0100 Subject: [PATCH 09/17] Updated dockerfile --- tools/Altinn.Correspondence.Dashboard/Dockerfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/Altinn.Correspondence.Dashboard/Dockerfile b/tools/Altinn.Correspondence.Dashboard/Dockerfile index 7c821b79e..af14f3dd2 100644 --- a/tools/Altinn.Correspondence.Dashboard/Dockerfile +++ b/tools/Altinn.Correspondence.Dashboard/Dockerfile @@ -9,18 +9,19 @@ ENV ASPNETCORE_URLS=http://+:2526 # This stage is used to build the service project FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build -ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj", "tools/Altinn.Correspondence.Dashboard/"] +COPY ["src/Altinn.Correspondence.Persistence/Altinn.Correspondence.Persistence.csproj", "src/Altinn.Correspondence.Persistence/"] +COPY ["src/Altinn.Correspondence.Integrations/Altinn.Correspondence.Integrations.csproj", "src/Altinn.Correspondence.Integrations/"] + RUN dotnet restore "tools/Altinn.Correspondence.Dashboard/Altinn.Correspondence.Dashboard.csproj" COPY . . WORKDIR "/src/tools/Altinn.Correspondence.Dashboard" -RUN dotnet build "./Altinn.Correspondence.Dashboard.csproj" -c $BUILD_CONFIGURATION -o /app/build +RUN dotnet build "Altinn.Correspondence.Dashboard.csproj" -c Release -o /app/build # This stage is used to publish the service project to be copied to the final stage FROM build AS publish -ARG BUILD_CONFIGURATION=Release -RUN dotnet publish "./Altinn.Correspondence.Dashboard.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false3 +RUN dotnet publish "Altinn.Correspondence.Dashboard.csproj" -c Release -o /app/publish /p:UseAppHost=false # This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) FROM base AS final From 98caa57f90ebc4bc49116d42f4752ef066d4cfb5 Mon Sep 17 00:00:00 2001 From: Ceredron <36594318+Ceredron@users.noreply.github.com> Date: Sat, 1 Mar 2025 18:53:24 +0100 Subject: [PATCH 10/17] Removed unused .http file --- tools/Altinn.Correspondence.Dashboard/app.http | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 tools/Altinn.Correspondence.Dashboard/app.http diff --git a/tools/Altinn.Correspondence.Dashboard/app.http b/tools/Altinn.Correspondence.Dashboard/app.http deleted file mode 100644 index 037c82862..000000000 --- a/tools/Altinn.Correspondence.Dashboard/app.http +++ /dev/null @@ -1,2 +0,0 @@ -# For more info on HTTP files go to https://aka.ms/vs/httpfile -GET https://localhost:7220/weatherforecast \ No newline at end of file From 658accced89800d48c6573d11c25fcb31a7a52e9 Mon Sep 17 00:00:00 2001 From: Ceredron <36594318+Ceredron@users.noreply.github.com> Date: Sun, 2 Mar 2025 16:52:01 +0100 Subject: [PATCH 11/17] Fixed bicep to include the necessary setup --- .azure/applications/dashboard.bicep | 26 -------- .azure/applications/dashboard/main.bicep | 65 +++++++++++++++++++ .azure/applications/dashboard/main.bicepparam | 4 ++ .azure/modules/containerApp/dashboard.bicep | 37 ----------- .github/workflows/deploy-dashboard.yml | 5 +- 5 files changed, 71 insertions(+), 66 deletions(-) delete mode 100644 .azure/applications/dashboard.bicep create mode 100644 .azure/applications/dashboard/main.bicep create mode 100644 .azure/applications/dashboard/main.bicepparam delete mode 100644 .azure/modules/containerApp/dashboard.bicep diff --git a/.azure/applications/dashboard.bicep b/.azure/applications/dashboard.bicep deleted file mode 100644 index 911391cc1..000000000 --- a/.azure/applications/dashboard.bicep +++ /dev/null @@ -1,26 +0,0 @@ -param location string -param environment string -param containerAppEnvironmentName string -param containerImage string -param minReplicas int = 1 -param maxReplicas int = 1 - -module containerApp '../modules/containerApp/dashboard.bicep' = { - name: 'dashboard' - params: { - name: 'altinn-corr-${environment}-dashboard' - location: location - environmentName: containerAppEnvironmentName - containerImage: containerImage - minReplicas: minReplicas - maxReplicas: maxReplicas - env: [ - { - name: 'ASPNETCORE_ENVIRONMENT' - value: environment - } - ] - } -} - -output dashboardUrl string = containerApp.outputs.url diff --git a/.azure/applications/dashboard/main.bicep b/.azure/applications/dashboard/main.bicep new file mode 100644 index 000000000..5c3753cab --- /dev/null +++ b/.azure/applications/dashboard/main.bicep @@ -0,0 +1,65 @@ +param location string +param containerImage string +param azureNamePrefix string +param keyVaultName string + +resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { + name: keyVaultName +} + +resource secret 'Microsoft.KeyVault/vaults/secrets@2021-06-01-preview' existing = { + parent: keyVault + name: 'correspondence-migration-connection-string' +} + +// Register the secret with the container app environment +resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: '${azureNamePrefix}-env' + location: location + properties: { + appLogsConfiguration: { + destination: 'log-analytics' + } + secrets: [ + { + name: 'correspondence-migration-connection-string' + value: secret.properties.value + } + ] + } +} + +resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { + name: 'dashboard' + location: location + properties: { + environmentId: '${azureNamePrefix}-env' + configuration: { + ingress: { + external: true + targetPort: 2526 + allowInsecure: false + } + } + template: { + containers: [ + { + name: 'dashboard' + image: containerImage + env: [ + { + name: 'DatabsaeOptions__ConnectionString' + value: secret.properties.value + } + ] + } + ] + scale: { + minReplicas: 1 + maxReplicas: 1 + } + } + } +} + +output dashboardUrl string = containerApp.outputs.url diff --git a/.azure/applications/dashboard/main.bicepparam b/.azure/applications/dashboard/main.bicepparam new file mode 100644 index 000000000..d2641a5b7 --- /dev/null +++ b/.azure/applications/dashboard/main.bicepparam @@ -0,0 +1,4 @@ +param azureNamePrefix = readEnvironmentVariable('AZURE_NAME_PREFIX') +param location = 'Norway East' +param containerImage = readEnvironmentVariable('containerImage') +param keyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') diff --git a/.azure/modules/containerApp/dashboard.bicep b/.azure/modules/containerApp/dashboard.bicep deleted file mode 100644 index 23a8e01a7..000000000 --- a/.azure/modules/containerApp/dashboard.bicep +++ /dev/null @@ -1,37 +0,0 @@ -param location string -param name string -param environmentName string -param containerImage string -param minReplicas int = 1 -param maxReplicas int = 1 -param env array = [] - -resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { - name: name - location: location - properties: { - environmentId: environmentName - configuration: { - ingress: { - external: true - targetPort: 2526 - allowInsecure: false - } - } - template: { - containers: [ - { - name: 'dashboard' - image: containerImage - env: env - } - ] - scale: { - minReplicas: minReplicas - maxReplicas: maxReplicas - } - } - } -} - -output url string = containerApp.properties.configuration.ingress.fqdn diff --git a/.github/workflows/deploy-dashboard.yml b/.github/workflows/deploy-dashboard.yml index e03aa8595..c3733d595 100644 --- a/.github/workflows/deploy-dashboard.yml +++ b/.github/workflows/deploy-dashboard.yml @@ -60,7 +60,6 @@ jobs: resourceGroupName: ${{ secrets.RESOURCE_GROUP }} template: .azure/applications/dashboard.bicep parameters: > - location=${{ secrets.LOCATION }} - environment=${{ github.event.inputs.environment }} - containerAppEnvironmentName=${{ secrets.CONTAINER_APP_ENVIRONMENT }} + AZURE_NAME_PREFIX: ${{ secrets.AZURE_NAME_PREFIX }} containerImage=ghcr.io/altinn/altinn-correspondence-dashboard:${{ github.sha }} + AZURE_ENVIRONMENT_KEY_VAULT_NAME: ${{ secrets.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} From 6c2b2264ab167190e38cb637ff212ca835d444c8 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Sun, 2 Mar 2025 21:51:48 +0100 Subject: [PATCH 12/17] FIx --- .azure/applications/dashboard/main.bicep | 39 ++++++++++++------- .azure/applications/dashboard/main.bicepparam | 2 + 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/.azure/applications/dashboard/main.bicep b/.azure/applications/dashboard/main.bicep index 5c3753cab..a6a1d9b1a 100644 --- a/.azure/applications/dashboard/main.bicep +++ b/.azure/applications/dashboard/main.bicep @@ -12,34 +12,45 @@ resource secret 'Microsoft.KeyVault/vaults/secrets@2021-06-01-preview' existing name: 'correspondence-migration-connection-string' } -// Register the secret with the container app environment -resource containerAppEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { - name: '${azureNamePrefix}-env' - location: location +resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { + name: '${keyVaultName}/add' properties: { - appLogsConfiguration: { - destination: 'log-analytics' - } - secrets: [ + accessPolicies: [ { - name: 'correspondence-migration-connection-string' - value: secret.properties.value + objectId: containerApp.identity.principalId + tenantId: subscription().tenantId + permissions: { + secrets: [ + 'get' + 'list' + ] + } } ] } -} +} resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { name: 'dashboard' location: location + identity: { + type: 'SystemAssigned' + } properties: { - environmentId: '${azureNamePrefix}-env' + environmentId: resourceId('Microsoft.App/managedEnvironments', '${azureNamePrefix}-env') configuration: { ingress: { external: true targetPort: 2526 allowInsecure: false } + secrets: [ + { + name: 'correspondence-migration-connection-string' + keyVaultUrl: '${keyVault.properties.vaultUri}secrets/correspondence-migration-connection-string' + identity: 'System' + } + ] } template: { containers: [ @@ -49,7 +60,7 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { env: [ { name: 'DatabsaeOptions__ConnectionString' - value: secret.properties.value + secretRef: 'correspondence-migration-connection-string' } ] } @@ -61,5 +72,3 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { } } } - -output dashboardUrl string = containerApp.outputs.url diff --git a/.azure/applications/dashboard/main.bicepparam b/.azure/applications/dashboard/main.bicepparam index d2641a5b7..b0171cc1a 100644 --- a/.azure/applications/dashboard/main.bicepparam +++ b/.azure/applications/dashboard/main.bicepparam @@ -1,3 +1,5 @@ +using './main.bicep' + param azureNamePrefix = readEnvironmentVariable('AZURE_NAME_PREFIX') param location = 'Norway East' param containerImage = readEnvironmentVariable('containerImage') From 230c20324797838d1deb6699a0a74e70b04d5b61 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Sun, 2 Mar 2025 22:07:03 +0100 Subject: [PATCH 13/17] Clean-up --- .azure/applications/dashboard/main.bicep | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.azure/applications/dashboard/main.bicep b/.azure/applications/dashboard/main.bicep index a6a1d9b1a..280b83168 100644 --- a/.azure/applications/dashboard/main.bicep +++ b/.azure/applications/dashboard/main.bicep @@ -7,11 +7,6 @@ resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { name: keyVaultName } -resource secret 'Microsoft.KeyVault/vaults/secrets@2021-06-01-preview' existing = { - parent: keyVault - name: 'correspondence-migration-connection-string' -} - resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { name: '${keyVaultName}/add' properties: { @@ -31,7 +26,7 @@ resource keyVaultAccessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07- } resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { - name: 'dashboard' + name: '${azureNamePrefix}-dashboard' location: location identity: { type: 'SystemAssigned' From bd2632b0443fb3d84b80c74d39372a835a88d9e9 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Sun, 2 Mar 2025 23:50:02 +0100 Subject: [PATCH 14/17] Add authentication to bicep --- .azure/applications/dashboard/main.bicep | 46 ++++++++++++++++++- .azure/applications/dashboard/main.bicepparam | 4 ++ .github/workflows/deploy-dashboard.yml | 4 ++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/.azure/applications/dashboard/main.bicep b/.azure/applications/dashboard/main.bicep index 280b83168..b65a03e60 100644 --- a/.azure/applications/dashboard/main.bicep +++ b/.azure/applications/dashboard/main.bicep @@ -2,6 +2,10 @@ param location string param containerImage string param azureNamePrefix string param keyVaultName string +param appRegistrationId string +param appRegistrationClientSecret string +param tenantId string +param allowedGroupId string resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' existing = { name: keyVaultName @@ -45,6 +49,10 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { keyVaultUrl: '${keyVault.properties.vaultUri}secrets/correspondence-migration-connection-string' identity: 'System' } + { + name: 'app-registration-client-secret' + value: appRegistrationClientSecret + } ] } template: { @@ -54,7 +62,7 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { image: containerImage env: [ { - name: 'DatabsaeOptions__ConnectionString' + name: 'DatabaseOptions__ConnectionString' secretRef: 'correspondence-migration-connection-string' } ] @@ -67,3 +75,39 @@ resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { } } } + +// Configure authentication for Container App +resource containerAppAuth 'Microsoft.App/containerApps/authConfigs@2023-05-01' = { + name: 'current' + parent: containerApp + properties: { + platform: { + enabled: true + } + identityProviders: { + azureActiveDirectory: { + enabled: true + registration: { + clientId: appRegistrationId + clientSecretSettingName: 'app-registration-client-secret' + openIdIssuer: 'https://sts.windows.net/${tenantId}/' + } + validation: { + allowedAudiences: [ + 'api://${appRegistrationId}' + ] + defaultAuthorizationPolicy: { + allowedPrincipals: { + groups: [ + allowedGroupId + ] + } + } + } + } + } + globalValidation: { + unauthenticatedClientAction: 'RedirectToLoginPage' + } + } +} diff --git a/.azure/applications/dashboard/main.bicepparam b/.azure/applications/dashboard/main.bicepparam index b0171cc1a..dc3310203 100644 --- a/.azure/applications/dashboard/main.bicepparam +++ b/.azure/applications/dashboard/main.bicepparam @@ -4,3 +4,7 @@ param azureNamePrefix = readEnvironmentVariable('AZURE_NAME_PREFIX') param location = 'Norway East' param containerImage = readEnvironmentVariable('containerImage') param keyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME') +param appRegistrationId = readEnvironmentVariable('AZURE_APP_REGISTRATION_ID') +param tenantId = readEnvironmentVariable('AZURE_TENANT_ID') +param allowedGroupId = readEnvironmentVariable('DASHBOARD_ALLOWED_GROUP_ID') +param appRegistrationClientSecret = readEnvironmentVariable('AZURE_APP_REGISTRATION_CLIENT_SECRET') diff --git a/.github/workflows/deploy-dashboard.yml b/.github/workflows/deploy-dashboard.yml index c3733d595..f0e24497c 100644 --- a/.github/workflows/deploy-dashboard.yml +++ b/.github/workflows/deploy-dashboard.yml @@ -63,3 +63,7 @@ jobs: AZURE_NAME_PREFIX: ${{ secrets.AZURE_NAME_PREFIX }} containerImage=ghcr.io/altinn/altinn-correspondence-dashboard:${{ github.sha }} AZURE_ENVIRONMENT_KEY_VAULT_NAME: ${{ secrets.AZURE_ENVIRONMENT_KEY_VAULT_NAME }} + AZURE_APP_REGISTRATION_ID: ${{ secrets.AZURE_APP_REGISTRATION_ID }} + AZURE_APP_REGISTRATION_CLIENT_SECRET: ${{ secrets.AZURE_APP_REGISTRATION_CLIENT_SECRET }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + DASHBOARD_ALLOWED_GROUP_ID: ${{ secrets.AZURE_TEST_ACCESS_CLIENT_ID }} From accefc2d5575aaad8c8d76221bfde0cf8701c311 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Sun, 2 Mar 2025 23:58:50 +0100 Subject: [PATCH 15/17] Delete old script as we do bicep now --- .../deploy-dashboard.sh | 115 ------------------ 1 file changed, 115 deletions(-) delete mode 100644 tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh diff --git a/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh b/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh deleted file mode 100644 index 37682b312..000000000 --- a/tools/Altinn.Correspondence.Dashboard/deploy-dashboard.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/bin/bash - -# Pre-requisites -# Install gh (sudo apt install gh) -# Install az tools (sudo apt install az), and run az login then select the correct subscription - -# Script to deploy Hangfire container app. -# This script will create a new App Registration and Service Principal, and deploy the Dashboard container app. -# It will also configure authentication for the container app. -# This was otherwise not possible to do using bicep as we usually would, hence the script as it will run as a user who can make service principals - -# Exit on error -set -e - -# Default values -ENVIRONMENT_NAME="" - -# Function to display usage -usage() { - echo "Usage: $0 -e " - echo "Example: $0 -e test" - exit 1 -} - -# Parse command line arguments -while getopts "e:i:" opt; do - case $opt in - e) ENVIRONMENT_NAME="$OPTARG";; - ?) usage;; - esac -done - -# Validate required parameters -if [ -z "$ENVIRONMENT_NAME" ]; then - echo "Error: Missing required parameters" - usage -fi - -# Get the latest git tag -GIT_TAG=$(git describe --tags --abbrev=0) -if [ -z "$GIT_TAG" ]; then - echo "Error: No git tag found" - exit 1 -fi - -# Set constants -LOCATION="Norway East" -APP_NAME="altinn-corr-${ENVIRONMENT_NAME}-dashboard-app" -RESOURCE_GROUP="altinn-corr-${ENVIRONMENT_NAME}-rg" -DOCKER_IMAGE_NAME="ghcr.io/altinn/altinn-correspondence-dashboard:${GIT_TAG}" - -echo "Building and pushing Hangfire Dashboard container..." -echo "Building Docker image..." -docker build -t $DOCKER_IMAGE_NAME -f Dockerfile ../.. - -# Login to GitHub packages -echo "Logging in to GitHub packages..." -gh auth login -w -s write:packages -gh auth setup-git -echo "Our username" -echo $(gh api user --jq '.login') -echo "Our password" -#echo $(gh auth status -t 2>&1 | grep Token | cut -d':' -f2 | xargs) - -docker login ghcr.io -u $(gh api user --jq '.login') -p $(gh auth status -t 2>&1 | grep Token | cut -d':' -f2 | xargs) - -# Push the image -echo "Pushing image to GitHub packages..." -docker push $DOCKER_IMAGE_NAME - -# Set the image parameter to the newly built image - -echo "Creating Container App with authentication..." -echo "Using Resource Group: $RESOURCE_GROUP" -echo "Location: $LOCATION" -echo "App Name: $APP_NAME" - -# Create the App Registration -echo "Creating App Registration..." -APP_ID=$(az ad app create --display-name "$APP_NAME" --query appId --output tsv) -echo "App Registration created with ID: $APP_ID" - -# Create service principal for the app -echo "Creating Service Principal..." -az ad sp create --id $APP_ID - -# Generate a secret for the app registration -echo "Generating client secret..." -CLIENT_SECRET=$(az ad app credential reset --id $APP_ID --query password --output tsv) - -# Create the Container App -echo "Creating Container App..." -az containerapp create \ - --name "$APP_NAME" \ - --resource-group "$RESOURCE_GROUP" \ - --environment "altinn-corr-$ENVIRONMENT_NAME-env" \ - --image "$DOCKER_IMAGE_NAME" \ - --target-port 80 \ - --ingress external - -# Configure authentication -echo "Configuring authentication..." -TENANT_ID=${az account show --query tenantId -o tsv} -az containerapp auth microsoft update \ - --name "$APP_NAME" \ - --resource-group "$RESOURCE_GROUP" \ - --client-id "$APP_ID" \ - --client-secret "$CLIENT_SECRET" \ - --tenant-id "$TENANT_ID" \ - --allowed-audiences "api://$APP_ID" - -echo "Container App deployment complete!" -echo "App Registration ID: $APP_ID" -echo "Please save these credentials securely." - From 431c257f840b003d5d6ad332050c4b87037a6fc7 Mon Sep 17 00:00:00 2001 From: Roar Mjelde <36594318+Ceredron@users.noreply.github.com> Date: Mon, 3 Mar 2025 08:16:50 +0100 Subject: [PATCH 16/17] Update .github/workflows/deploy-dashboard.yml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/workflows/deploy-dashboard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-dashboard.yml b/.github/workflows/deploy-dashboard.yml index f0e24497c..9da299607 100644 --- a/.github/workflows/deploy-dashboard.yml +++ b/.github/workflows/deploy-dashboard.yml @@ -58,7 +58,7 @@ jobs: with: scope: resourcegroup resourceGroupName: ${{ secrets.RESOURCE_GROUP }} - template: .azure/applications/dashboard.bicep + template: .azure/applications/dashboard/main.bicep parameters: > AZURE_NAME_PREFIX: ${{ secrets.AZURE_NAME_PREFIX }} containerImage=ghcr.io/altinn/altinn-correspondence-dashboard:${{ github.sha }} From eab8b8f8db3a4784d3bc65c3cdb81ba547fa4b89 Mon Sep 17 00:00:00 2001 From: Roar Mjelde Date: Mon, 3 Mar 2025 11:22:58 +0100 Subject: [PATCH 17/17] Fixed auth config --- .azure/applications/dashboard/main.bicep | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.azure/applications/dashboard/main.bicep b/.azure/applications/dashboard/main.bicep index b65a03e60..a83401447 100644 --- a/.azure/applications/dashboard/main.bicep +++ b/.azure/applications/dashboard/main.bicep @@ -87,6 +87,9 @@ resource containerAppAuth 'Microsoft.App/containerApps/authConfigs@2023-05-01' = identityProviders: { azureActiveDirectory: { enabled: true + login: { + disableWWWAuthenticate: false + } registration: { clientId: appRegistrationId clientSecretSettingName: 'app-registration-client-secret' @@ -101,13 +104,24 @@ resource containerAppAuth 'Microsoft.App/containerApps/authConfigs@2023-05-01' = groups: [ allowedGroupId ] + identities: [ + allowedGroupId + ] } + allowedApplications: [ + '${appRegistrationId}' + ] + } + jwtClaimChecks: { + allowedClientApplications: [ + '${appRegistrationId}' + ] + allowedGroups: [ + allowedGroupId + ] } } } } - globalValidation: { - unauthenticatedClientAction: 'RedirectToLoginPage' - } } }