Skip to content

Commit

Permalink
Setup Azure AppConfiguration hence enable logging to SEQ
Browse files Browse the repository at this point in the history
  • Loading branch information
mburumaxwell committed Sep 20, 2023
1 parent c49b629 commit ee147d8
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 6 deletions.
27 changes: 27 additions & 0 deletions server/Tingle.Dependabot/AzureAppConfigurationStartupFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Tingle.Dependabot;

internal class AzureAppConfigurationStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
{
var configuration = builder is WebApplication webApp
? webApp.Configuration
: builder.ApplicationServices.GetRequiredService<IConfiguration>();

/*
* If the endpoint is not null, then AppConfiguration services were added.
* This means we can add the middleware to the pipeline.
* Otherwise it would throw an exception.
*/
var endpoint = configuration.GetValue<Uri?>("AzureAppConfig:Endpoint");
if (endpoint is not null)
{
builder.UseAzureAppConfiguration();
}

next(builder);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Azure.Identity;

namespace Microsoft.Extensions.Configuration;

/// <summary>Extensions for <see cref="ConfigurationManager"/>.</summary>
public static class ConfigurationManagerExtensions
{
/// <summary>
/// Adds standard Azure AppConfiguration provider and services.
/// </summary>
/// <param name="manager">The <see cref="ConfigurationManager"/> to be configured.</param>
/// <param name="environment">The <see cref="IHostEnvironment"/> to use.</param>
/// <returns></returns>
public static ConfigurationManager AddStandardAzureAppConfiguration(this ConfigurationManager manager, IHostEnvironment environment)
{
var section = manager.GetSection("AzureAppConfig");
var endpoint = section.GetValue<Uri?>("Endpoint");
var label = section.GetValue<string?>("Label") ?? environment.EnvironmentName;
if (endpoint is not null)
{
var cacheExpiration = section.GetValue<TimeSpan?>("CacheExpiration") ?? TimeSpan.FromHours(1);
var cacheExpirationInterval = section.GetValue<TimeSpan?>("CacheExpirationInterval") ?? TimeSpan.FromMinutes(30);
manager.AddAzureAppConfiguration(options =>
{
options.Connect(endpoint: endpoint, credential: new DefaultAzureCredential())
.Select("*", label)
.ConfigureRefresh(o =>
{
o.Register("Refresh", label, refreshAll: true) // key to use to trigger refresh
.SetCacheExpiration(cacheExpiration);
})
.UseFeatureFlags(o =>
{
o.Label = label;
o.CacheExpirationInterval = cacheExpirationInterval;
});
});
}

return manager;
}
}
5 changes: 5 additions & 0 deletions server/Tingle.Dependabot/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

var builder = WebApplication.CreateBuilder(args);

// Add Azure AppConfiguration
builder.Configuration.AddStandardAzureAppConfiguration(builder.Environment);
builder.Services.AddAzureAppConfiguration();
builder.Services.AddSingleton<IStartupFilter, AzureAppConfigurationStartupFilter>(); // Use IStartupFilter to setup AppConfiguration middleware correctly

// Add Serilog
builder.Services.AddSerilog(builder =>
{
Expand Down
1 change: 1 addition & 0 deletions server/Tingle.Dependabot/Tingle.Dependabot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.11" />
<PackageReference Include="Microsoft.Azure.AppConfiguration.AspNetCore" Version="6.1.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.11" PrivateAssets="All" />
Expand Down
7 changes: 1 addition & 6 deletions server/Tingle.Dependabot/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
{
"Logging": {
"ApplicationInsights": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning" //"Error"
}
},
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
Expand All @@ -18,6 +12,7 @@
},
"AllowedHosts": "*",

"AzureAppConfig:Endpoint": null, // only set a value in production or in secrets
"ConnectionStrings:Sql": "Server=(localdb)\\mssqllocaldb;Database=dependabot;Trusted_Connection=True;MultipleActiveResultSets=true",

"Authentication": {
Expand Down
29 changes: 29 additions & 0 deletions server/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ resource serviceBusNamespace 'Microsoft.ServiceBus/namespaces@2021-11-01' = {
resource authorizationRule 'AuthorizationRules' existing = { name: 'RootManageSharedAccessKey' }
}

/* AppConfiguration */
resource appConfiguration 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = {
name: '${name}-${collisionSuffix}'
location: location
properties: { softDeleteRetentionInDays: 0 /* Free does not support this */ }
sku: { name: 'free' }
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {/*ttk bug*/ }
}
}
}

/* Storage Account */
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: '${name}${collisionSuffix}' // hyphens not allowed
Expand Down Expand Up @@ -277,12 +291,18 @@ resource app 'Microsoft.App/containerApps@2023-05-01' = {
{ name: 'ASPNETCORE_FORWARDEDHEADERS_ENABLED', value: 'true' } // Application is behind proxy
{ name: 'EFCORE_PERFORM_MIGRATIONS', value: 'true' } // Perform migrations on startup

{ name: 'AzureAppConfig__Endpoint', value: appConfiguration.properties.endpoint }
{ name: 'AzureAppConfig__Label', value: 'Production' }

{ name: 'ApplicationInsights__ConnectionString', secretRef: 'connection-strings-application-insights' }
{ name: 'ConnectionStrings__Sql', secretRef: 'connection-strings-sql' }

{ name: 'DistributedLocking__FilePath', value: '/mnt/distributed-locks' }

{ name: 'Logging__ApplicationInsights__LogLevel__Default', value: 'None' } // do not send logs to application insights (duplicates LogAnalytics)
{ name: 'Logging__Seq__LogLevel__Default', value: 'Warning' }
{ name: 'Logging__Seq__ServerUrl', value: '' } // set via AppConfig
{ name: 'Logging__Seq__ApiKey', value: '' } // set via AppConfig

{ name: 'Workflow__SynchronizeOnStartup', value: synchronizeOnStartup ? 'true' : 'false' }
{ name: 'Workflow__CreateOrUpdateWebhooksOnStartup', value: createOrUpdateWebhooksOnStartup ? 'true' : 'false' }
Expand Down Expand Up @@ -367,6 +387,15 @@ resource serviceBusDataOwnerRoleAssignment 'Microsoft.Authorization/roleAssignme
principalType: 'ServicePrincipal'
}
}
resource appConfigurationDataReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(managedIdentity.id, 'AppConfigurationDataReader')
scope: resourceGroup()
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')
principalId: managedIdentity.properties.principalId
principalType: 'ServicePrincipal'
}
}
resource storageBlobDataContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(managedIdentity.id, 'StorageBlobDataContributor')
scope: resourceGroup()
Expand Down
55 changes: 55 additions & 0 deletions server/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,27 @@
"name": "Basic"
}
},
{
"type": "Microsoft.AppConfiguration/configurationStores",
"apiVersion": "2023-03-01",
"name": "[format('{0}-{1}', parameters('name'), variables('collisionSuffix'))]",
"location": "[parameters('location')]",
"properties": {
"softDeleteRetentionInDays": 0
},
"sku": {
"name": "free"
},
"identity": {
"type": "UserAssigned",
"userAssignedIdentities": {
"[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')))]": {}
}
},
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]"
]
},
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2022-09-01",
Expand Down Expand Up @@ -426,6 +447,14 @@
"name": "EFCORE_PERFORM_MIGRATIONS",
"value": "true"
},
{
"name": "AzureAppConfig__Endpoint",
"value": "[reference(resourceId('Microsoft.AppConfiguration/configurationStores', format('{0}-{1}', parameters('name'), variables('collisionSuffix'))), '2023-03-01').endpoint]"
},
{
"name": "AzureAppConfig__Label",
"value": "Production"
},
{
"name": "ApplicationInsights__ConnectionString",
"secretRef": "connection-strings-application-insights"
Expand All @@ -442,6 +471,18 @@
"name": "Logging__ApplicationInsights__LogLevel__Default",
"value": "None"
},
{
"name": "Logging__Seq__LogLevel__Default",
"value": "Warning"
},
{
"name": "Logging__Seq__ServerUrl",
"value": ""
},
{
"name": "Logging__Seq__ApiKey",
"value": ""
},
{
"name": "Workflow__SynchronizeOnStartup",
"value": "[if(parameters('synchronizeOnStartup'), 'true', 'false')]"
Expand Down Expand Up @@ -590,6 +631,7 @@
}
},
"dependsOn": [
"[resourceId('Microsoft.AppConfiguration/configurationStores', format('{0}-{1}', parameters('name'), variables('collisionSuffix')))]",
"[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]",
"[resourceId('Microsoft.Insights/components', parameters('name'))]",
"[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]",
Expand Down Expand Up @@ -625,6 +667,19 @@
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]"
]
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), 'AppConfigurationDataReader')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')]",
"principalId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2023-01-31').principalId]",
"principalType": "ServicePrincipal"
},
"dependsOn": [
"[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]"
]
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
Expand Down

0 comments on commit ee147d8

Please sign in to comment.