Multiple line secrets or configuration do not work in Aspire per default. An example of this is using a PEM file for certificates. This posts shows how the multiple line configuration parameters can be setup in Aspire, ASP.NET Core and works with user secrets and Azure default deployments.
Code: https://github.com/swiss-ssi-group/swiyu-passkeys-idp-loi-loa

Adding an base64 encoding layer
To workaround this Aspire bug, we can add a base64 encoding layer between the Aspire parameters and use the multiple line configuration. This needs to work on Linux and Windows container deployments and with developer user secrets. I work in my local development using Visual Studio. I created a helper class for loading the PEM string from a base64 string. The helper class can be used to create the base64 strings, or read them.
using Microsoft.Extensions.Configuration;
using System.Text;
namespace Idp.Swiyu.Passkeys.ServiceDefaults;
public static class ConfigConverter
{
public static string GetPemFromBase64Config(string config, IConfiguration configuration)
{
var base64String = configuration.GetValue<string>(config);
if (string.IsNullOrEmpty(base64String))
{
throw new ArgumentException($"PEM Configuration value for '{config}' is missing or empty.");
}
return Encoding.UTF8.GetString(Convert.FromBase64String(base64String));
}
public static string GetPemFromBase64(string base64String)
{
return Encoding.UTF8.GetString(Convert.FromBase64String(base64String));
}
public static string CreateBase64FromPem(string pem)
{
var base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(pem));
return base64String;
}
}
Using the configuration inside an application
The configuration can then be used inside any ASP.NET Core application using the ConfigConverter helper class. It reads in the name of the configuration and decodes this to the original value.
var webDpopClientPrivatePem = ConfigConverter.GetPemFromBase64Config("WebDpopClientPrivatePemBase64", builder.Configuration);
var webDpopClientPublicPem = ConfigConverter.GetPemFromBase64Config("WebDpopClientPublicPemBase64", builder.Configuration);
var ecdsaCertificate = X509Certificate2.CreateFromPem(webDpopClientPublicPem, webDpopClientPrivatePem);
var ecdsaCertificateKey = new ECDsaSecurityKey(ecdsaCertificate.GetECDsaPrivateKey());
Loading the parameters in Aspire hosting project
In the Aspire host project, the configuration must be read directly and passed into the application, container or service using the WithEnvironment method.
var webOidcClientPrivatePemBase64 = builder.AddParameter("WebOidcClientPrivatePemBase64", secret: true);
var webOidcClientPublicPemBase64 = builder.AddParameter("WebOidcClientPublicPemBase64");
var webDpopClientPrivatePemBase64 = builder.AddParameter("WebDpopClientPrivatePemBase64", secret: true);
var webDpopClientPublicPemBase64 = builder.AddParameter("WebDpopClientPublicPemBase64");
builder.AddProject<Projects.Idp_Swiyu_Passkeys_Web>(WEB_CLIENT)
.WithExternalHttpEndpoints()
.WithReference(apiService)
.WaitFor(apiService)
.WithEnvironment("WebOidcAuthority", webOidcAuthority)
.WithEnvironment("WebOidcClientId", webOidcClientId)
.WithEnvironment("WebOidcClientPrivatePemBase64", webOidcClientPrivatePemBase64)
.WithEnvironment("WebOidcClientPublicPemBase64", webOidcClientPublicPemBase64)
.WithEnvironment("WebDpopClientPrivatePemBase64", webDpopClientPrivatePemBase64)
.WithEnvironment("WebDpopClientPublicPemBase64", webDpopClientPublicPemBase64)
.WithHttpHealthCheck("/health")
.WaitFor(identityProvider)
.WithReference(identityProvider);
The configuration values are stored using the base64 format. These are still secrets, the values are encoded, not encrypted.
"Parameters:WebDpopClientPublicPemBase64": "LS0tLS...
Now when the application is deployed, it just works, without requiring any manually configuration setup.
Links:
https://aspire.dev/app-host/configuration/?aspire-lang=csharp
