up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OpenTelemetry.Instrumentation.AspNetCore;
|
||||
using OpenTelemetry.Instrumentation.Runtime;
|
||||
using OpenTelemetry.Metrics;
|
||||
@@ -16,48 +16,48 @@ using StellaOps.Configuration;
|
||||
using StellaOps.Telemetry.Core;
|
||||
using StellaOps.Registry.TokenService;
|
||||
using StellaOps.Registry.TokenService.Observability;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Configuration.AddStellaOpsDefaults(options =>
|
||||
{
|
||||
options.BasePath = builder.Environment.ContentRootPath;
|
||||
options.EnvironmentPrefix = "REGISTRY_TOKEN_";
|
||||
options.ConfigureBuilder = configurationBuilder =>
|
||||
{
|
||||
configurationBuilder.AddYamlFile("../etc/registry-token.yaml", optional: true, reloadOnChange: true);
|
||||
};
|
||||
});
|
||||
|
||||
var bootstrapOptions = builder.Configuration.BindOptions<RegistryTokenServiceOptions>(
|
||||
RegistryTokenServiceOptions.SectionName,
|
||||
(opts, _) => opts.Validate());
|
||||
|
||||
builder.Host.UseSerilog((context, services, loggerConfiguration) =>
|
||||
{
|
||||
loggerConfiguration
|
||||
.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console();
|
||||
});
|
||||
|
||||
builder.Services.AddOptions<RegistryTokenServiceOptions>()
|
||||
.Bind(builder.Configuration.GetSection(RegistryTokenServiceOptions.SectionName))
|
||||
.PostConfigure(options => options.Validate())
|
||||
.ValidateOnStart();
|
||||
|
||||
builder.Services.AddSingleton(TimeProvider.System);
|
||||
builder.Services.AddSingleton<RegistryTokenMetrics>();
|
||||
builder.Services.AddSingleton<PlanRegistry>(sp =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<RegistryTokenServiceOptions>>().Value;
|
||||
return new PlanRegistry(options);
|
||||
});
|
||||
builder.Services.AddSingleton<RegistryTokenIssuer>();
|
||||
|
||||
builder.Services.AddHealthChecks().AddCheck("self", () => Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Healthy());
|
||||
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Configuration.AddStellaOpsDefaults(options =>
|
||||
{
|
||||
options.BasePath = builder.Environment.ContentRootPath;
|
||||
options.EnvironmentPrefix = "REGISTRY_TOKEN_";
|
||||
options.ConfigureBuilder = configurationBuilder =>
|
||||
{
|
||||
configurationBuilder.AddYamlFile("../etc/registry-token.yaml", optional: true, reloadOnChange: true);
|
||||
};
|
||||
});
|
||||
|
||||
var bootstrapOptions = builder.Configuration.BindOptions<RegistryTokenServiceOptions>(
|
||||
RegistryTokenServiceOptions.SectionName,
|
||||
(opts, _) => opts.Validate());
|
||||
|
||||
builder.Host.UseSerilog((context, services, loggerConfiguration) =>
|
||||
{
|
||||
loggerConfiguration
|
||||
.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console();
|
||||
});
|
||||
|
||||
builder.Services.AddOptions<RegistryTokenServiceOptions>()
|
||||
.Bind(builder.Configuration.GetSection(RegistryTokenServiceOptions.SectionName))
|
||||
.PostConfigure(options => options.Validate())
|
||||
.ValidateOnStart();
|
||||
|
||||
builder.Services.AddSingleton(TimeProvider.System);
|
||||
builder.Services.AddSingleton<RegistryTokenMetrics>();
|
||||
builder.Services.AddSingleton<PlanRegistry>(sp =>
|
||||
{
|
||||
var options = sp.GetRequiredService<IOptions<RegistryTokenServiceOptions>>().Value;
|
||||
return new PlanRegistry(options);
|
||||
});
|
||||
builder.Services.AddSingleton<RegistryTokenIssuer>();
|
||||
|
||||
builder.Services.AddHealthChecks().AddCheck("self", () => Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckResult.Healthy());
|
||||
|
||||
builder.Services.AddAirGapEgressPolicy(builder.Configuration);
|
||||
builder.Services.AddStellaOpsTelemetry(
|
||||
builder.Configuration,
|
||||
@@ -72,111 +72,111 @@ builder.Services.AddStellaOpsTelemetry(
|
||||
tracerBuilder.AddAspNetCoreInstrumentation();
|
||||
tracerBuilder.AddHttpClientInstrumentation();
|
||||
});
|
||||
|
||||
builder.Services.AddStellaOpsResourceServerAuthentication(
|
||||
builder.Configuration,
|
||||
configurationSection: null,
|
||||
configure: resourceOptions =>
|
||||
{
|
||||
resourceOptions.Authority = bootstrapOptions.Authority.Issuer;
|
||||
resourceOptions.RequireHttpsMetadata = bootstrapOptions.Authority.RequireHttpsMetadata;
|
||||
resourceOptions.MetadataAddress = bootstrapOptions.Authority.MetadataAddress;
|
||||
|
||||
resourceOptions.Audiences.Clear();
|
||||
foreach (var audience in bootstrapOptions.Authority.Audiences)
|
||||
{
|
||||
resourceOptions.Audiences.Add(audience);
|
||||
}
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
var scopes = bootstrapOptions.Authority.RequiredScopes.Count == 0
|
||||
? new[] { "registry.token.issue" }
|
||||
: bootstrapOptions.Authority.RequiredScopes.ToArray();
|
||||
|
||||
options.AddPolicy("registry.token.issue", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.Requirements.Add(new StellaOpsScopeRequirement(scopes));
|
||||
policy.AddAuthenticationSchemes(StellaOpsAuthenticationDefaults.AuthenticationScheme);
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapHealthChecks("/healthz");
|
||||
|
||||
app.MapGet("/token", (
|
||||
HttpContext context,
|
||||
[FromServices] IOptions<RegistryTokenServiceOptions> options,
|
||||
[FromServices] RegistryTokenIssuer issuer) =>
|
||||
{
|
||||
var serviceOptions = options.Value;
|
||||
|
||||
var service = context.Request.Query["service"].FirstOrDefault()?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(service))
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "The 'service' query parameter is required.",
|
||||
statusCode: StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
if (serviceOptions.Registry.AllowedServices.Count > 0 &&
|
||||
!serviceOptions.Registry.AllowedServices.Contains(service, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "The requested registry service is not permitted for this installation.",
|
||||
statusCode: StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
IReadOnlyList<RegistryAccessRequest> accessRequests;
|
||||
try
|
||||
{
|
||||
accessRequests = RegistryScopeParser.Parse(context.Request.Query);
|
||||
}
|
||||
catch (InvalidScopeException ex)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
if (accessRequests.Count == 0)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "At least one scope must be requested.",
|
||||
statusCode: StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = issuer.IssueToken(context.User, service, accessRequests);
|
||||
|
||||
return Results.Json(new
|
||||
{
|
||||
token = response.Token,
|
||||
expires_in = response.ExpiresIn,
|
||||
issued_at = response.IssuedAt.UtcDateTime.ToString("O"),
|
||||
issued_token_type = "urn:ietf:params:oauth:token-type:access_token"
|
||||
});
|
||||
}
|
||||
catch (RegistryTokenException ex)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status403Forbidden);
|
||||
}
|
||||
})
|
||||
.WithName("GetRegistryToken")
|
||||
.RequireAuthorization("registry.token.issue")
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest)
|
||||
.ProducesProblem(StatusCodes.Status403Forbidden);
|
||||
|
||||
app.Run();
|
||||
|
||||
builder.Services.AddStellaOpsResourceServerAuthentication(
|
||||
builder.Configuration,
|
||||
configurationSection: null,
|
||||
configure: resourceOptions =>
|
||||
{
|
||||
resourceOptions.Authority = bootstrapOptions.Authority.Issuer;
|
||||
resourceOptions.RequireHttpsMetadata = bootstrapOptions.Authority.RequireHttpsMetadata;
|
||||
resourceOptions.MetadataAddress = bootstrapOptions.Authority.MetadataAddress;
|
||||
|
||||
resourceOptions.Audiences.Clear();
|
||||
foreach (var audience in bootstrapOptions.Authority.Audiences)
|
||||
{
|
||||
resourceOptions.Audiences.Add(audience);
|
||||
}
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
var scopes = bootstrapOptions.Authority.RequiredScopes.Count == 0
|
||||
? new[] { "registry.token.issue" }
|
||||
: bootstrapOptions.Authority.RequiredScopes.ToArray();
|
||||
|
||||
options.AddPolicy("registry.token.issue", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.Requirements.Add(new StellaOpsScopeRequirement(scopes));
|
||||
policy.AddAuthenticationSchemes(StellaOpsAuthenticationDefaults.AuthenticationScheme);
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapHealthChecks("/healthz");
|
||||
|
||||
app.MapGet("/token", (
|
||||
HttpContext context,
|
||||
[FromServices] IOptions<RegistryTokenServiceOptions> options,
|
||||
[FromServices] RegistryTokenIssuer issuer) =>
|
||||
{
|
||||
var serviceOptions = options.Value;
|
||||
|
||||
var service = context.Request.Query["service"].FirstOrDefault()?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(service))
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "The 'service' query parameter is required.",
|
||||
statusCode: StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
if (serviceOptions.Registry.AllowedServices.Count > 0 &&
|
||||
!serviceOptions.Registry.AllowedServices.Contains(service, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "The requested registry service is not permitted for this installation.",
|
||||
statusCode: StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
IReadOnlyList<RegistryAccessRequest> accessRequests;
|
||||
try
|
||||
{
|
||||
accessRequests = RegistryScopeParser.Parse(context.Request.Query);
|
||||
}
|
||||
catch (InvalidScopeException ex)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
if (accessRequests.Count == 0)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: "At least one scope must be requested.",
|
||||
statusCode: StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = issuer.IssueToken(context.User, service, accessRequests);
|
||||
|
||||
return Results.Json(new
|
||||
{
|
||||
token = response.Token,
|
||||
expires_in = response.ExpiresIn,
|
||||
issued_at = response.IssuedAt.UtcDateTime.ToString("O"),
|
||||
issued_token_type = "urn:ietf:params:oauth:token-type:access_token"
|
||||
});
|
||||
}
|
||||
catch (RegistryTokenException ex)
|
||||
{
|
||||
return Results.Problem(
|
||||
detail: ex.Message,
|
||||
statusCode: StatusCodes.Status403Forbidden);
|
||||
}
|
||||
})
|
||||
.WithName("GetRegistryToken")
|
||||
.RequireAuthorization("registry.token.issue")
|
||||
.Produces(StatusCodes.Status200OK)
|
||||
.ProducesProblem(StatusCodes.Status400BadRequest)
|
||||
.ProducesProblem(StatusCodes.Status403Forbidden);
|
||||
|
||||
app.Run();
|
||||
using StellaOps.AirGap.Policy;
|
||||
|
||||
Reference in New Issue
Block a user