A Keycloak container runs the identity service alongside an Aspire-hosted application. For an online shop, the Aspire host registers Keycloak as a resource, then gives the API and web frontend references to it. section 2.4
Wire it into the host in three steps:
- Define a KeycloakResource derived from ContainerResource and implementing IResourceWithServiceDiscovery. Store the client secret on the resource so it can be passed to Keycloak and its client. section 2.4
- Register it with AddResource(), configure the Keycloak image, HTTP endpoint and environment variables, then bind-mount the realm files for import. section 2.4
- Reference it from the API and frontend, and use WaitFor(idp) so those services wait for the identity provider. Pass the frontend's client secret through Identity__ClientSecret. section 2.4
Listing 2.1 Adding a Keycloak container
public static IResourceBuilder<KeycloakResource>
AddKeycloakContainer(
this IDistributedApplicationBuilder builder,
string name,
int? port = null,
string? tag = null)
{
var keycloakContainer = new KeycloakResource(name) #1
{
ClientSecret = "some_secret"
};
var keycloak = builder
.AddResource(keycloakContainer) #2
.WithAnnotation(new ContainerImageAnnotation #3
{
Registry = "quay.io",
Image = "keycloak/keycloak",
Tag = tag ?? "latest"
})
.WithHttpEndpoint(port: port, #4
targetPort: 8080)
.WithEnvironment("KEYCLOAK_ADMIN", "admin") #5
.WithEnvironment("KEYCLOAK_ADMIN_PASSWORD",
"admin")
.WithEnvironment("WEBAPP_CLIENT_SECRET",
keycloakContainer.ClientSecret);
if (builder.ExecutionContext.IsRunMode) #6
{
keycloak.WithArgs("start-dev");
}
else
{
keycloak.WithArgs("start");
}
return keycloak;
}
The container registration sets the image, target port and environment variables; AddResource() allows the custom resource to carry the client secret. section 2.4
Listing 2.2 Importing the Keycloak realms
public static IResourceBuilder<KeycloakResource>
ImportRealms(this IResourceBuilder<KeycloakResource>
builder,
string source)
{
builder
.WithBindMount(source,
"/opt/keycloak/data/import")
.WithAnnotation(
new CommandLineArgsCallbackAnnotation(
args =>
{
args.Clear();
if (builder.ApplicationBuilder
.ExecutionContext.IsRunMode)
{
args.Add("start-dev");
}
else
{
args.Add("start");
}
args.Add("--import-realm");
}));
return builder;
}
Realm import mounts the source directory and selects start-dev in run mode or start otherwise, adding --import-realm in either case. section 2.4
