This commit is contained in:
		| @@ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| @@ -28,16 +29,17 @@ using StellaOps.Authority.Storage.Mongo.Initialization; | ||||
| using StellaOps.Authority.Storage.Mongo.Stores; | ||||
| using StellaOps.Authority.RateLimiting; | ||||
| using StellaOps.Configuration; | ||||
| using StellaOps.Plugin.DependencyInjection; | ||||
| using StellaOps.Plugin.Hosting; | ||||
| using StellaOps.Authority.OpenIddict.Handlers; | ||||
| using System.Linq; | ||||
| using StellaOps.Cryptography.Audit; | ||||
| using StellaOps.Cryptography.DependencyInjection; | ||||
| using StellaOps.Authority.Permalinks; | ||||
| using StellaOps.Authority.Revocation; | ||||
| using StellaOps.Authority.Signing; | ||||
| using StellaOps.Cryptography; | ||||
| using StellaOps.Plugin.DependencyInjection; | ||||
| using StellaOps.Plugin.Hosting; | ||||
| using StellaOps.Authority.OpenIddict.Handlers; | ||||
| using System.Linq; | ||||
| using StellaOps.Cryptography.Audit; | ||||
| using StellaOps.Cryptography.DependencyInjection; | ||||
| using StellaOps.Authority.Permalinks; | ||||
| using StellaOps.Authority.Revocation; | ||||
| using StellaOps.Authority.Signing; | ||||
| using StellaOps.Cryptography; | ||||
| using StellaOps.Cryptography.Kms; | ||||
| using StellaOps.Authority.Storage.Mongo.Documents; | ||||
| using StellaOps.Authority.Security; | ||||
| using StellaOps.Auth.Abstractions; | ||||
| @@ -162,15 +164,36 @@ else | ||||
| builder.Services.AddScoped<ValidateDpopProofHandler>(); | ||||
| #endif | ||||
|  | ||||
| builder.Services.AddRateLimiter(rateLimiterOptions => | ||||
| { | ||||
|     AuthorityRateLimiter.Configure(rateLimiterOptions, authorityOptions); | ||||
| }); | ||||
|  | ||||
| builder.Services.AddStellaOpsCrypto(); | ||||
| builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IAuthoritySigningKeySource, FileAuthoritySigningKeySource>()); | ||||
| builder.Services.AddSingleton<AuthoritySigningKeyManager>(); | ||||
| builder.Services.AddSingleton<VulnPermalinkService>(); | ||||
| builder.Services.AddRateLimiter(rateLimiterOptions => | ||||
| { | ||||
|     AuthorityRateLimiter.Configure(rateLimiterOptions, authorityOptions); | ||||
| }); | ||||
|  | ||||
| var requiresKms = string.Equals(authorityOptions.Signing.KeySource, "kms", StringComparison.OrdinalIgnoreCase) | ||||
|     || authorityOptions.Signing.AdditionalKeys.Any(k => string.Equals(k.Source, "kms", StringComparison.OrdinalIgnoreCase)); | ||||
|  | ||||
| if (requiresKms) | ||||
| { | ||||
|     if (string.IsNullOrWhiteSpace(authorityOptions.Signing.KeyPassphrase)) | ||||
|     { | ||||
|         throw new InvalidOperationException("Authority signing with source 'kms' requires signing.keyPassphrase to be configured."); | ||||
|     } | ||||
|  | ||||
|     var kmsRoot = Path.Combine(builder.Environment.ContentRootPath, "kms"); | ||||
|     builder.Services.AddFileKms(options => | ||||
|     { | ||||
|         options.RootPath = kmsRoot; | ||||
|         options.Password = authorityOptions.Signing.KeyPassphrase!; | ||||
|         options.Algorithm = authorityOptions.Signing.Algorithm; | ||||
|     }); | ||||
|  | ||||
|     builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IAuthoritySigningKeySource, KmsAuthoritySigningKeySource>()); | ||||
| } | ||||
|  | ||||
| builder.Services.AddStellaOpsCrypto(); | ||||
| builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IAuthoritySigningKeySource, FileAuthoritySigningKeySource>()); | ||||
| builder.Services.AddSingleton<AuthoritySigningKeyManager>(); | ||||
| builder.Services.AddSingleton<VulnPermalinkService>(); | ||||
|  | ||||
| AuthorityPluginContext[] pluginContexts = AuthorityPluginConfigurationLoader | ||||
|     .Load(authorityOptions, builder.Environment.ContentRootPath) | ||||
|   | ||||
| @@ -0,0 +1,59 @@ | ||||
| using System.Collections.Generic; | ||||
| using StellaOps.Cryptography; | ||||
| using StellaOps.Cryptography.Kms; | ||||
|  | ||||
| namespace StellaOps.Authority.Signing; | ||||
|  | ||||
| internal sealed class KmsAuthoritySigningKeySource : IAuthoritySigningKeySource | ||||
| { | ||||
|     private readonly IKmsClient _kmsClient; | ||||
|  | ||||
|     public KmsAuthoritySigningKeySource(IKmsClient kmsClient) | ||||
|         => _kmsClient = kmsClient ?? throw new ArgumentNullException(nameof(kmsClient)); | ||||
|  | ||||
|     public bool CanLoad(string source) | ||||
|         => string.Equals(source, "kms", StringComparison.OrdinalIgnoreCase); | ||||
|  | ||||
|     public CryptoSigningKey Load(AuthoritySigningKeyRequest request) | ||||
|     { | ||||
|         ArgumentNullException.ThrowIfNull(request); | ||||
|  | ||||
|         if (!CanLoad(request.Source)) | ||||
|         { | ||||
|             throw new InvalidOperationException($"KMS signing key source cannot load '{request.Source}'."); | ||||
|         } | ||||
|  | ||||
|         var keyId = (request.Location ?? string.Empty).Trim(); | ||||
|         if (string.IsNullOrWhiteSpace(keyId)) | ||||
|         { | ||||
|             throw new InvalidOperationException("KMS signing keys require signing.keyPath/location to specify the key identifier."); | ||||
|         } | ||||
|  | ||||
|         request.AdditionalMetadata?.TryGetValue(KmsMetadataKeys.Version, out var versionId); | ||||
|         var material = _kmsClient.ExportAsync(keyId, versionId).GetAwaiter().GetResult(); | ||||
|  | ||||
|         var parameters = new ECParameters | ||||
|         { | ||||
|             Curve = ECCurve.NamedCurves.nistP256, | ||||
|             D = material.D.ToArray(), | ||||
|             Q = new ECPoint | ||||
|             { | ||||
|                 X = material.Qx.ToArray(), | ||||
|                 Y = material.Qy.ToArray(), | ||||
|             }, | ||||
|         }; | ||||
|  | ||||
|         var metadata = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase) | ||||
|         { | ||||
|             [KmsMetadataKeys.Version] = material.VersionId | ||||
|         }; | ||||
|  | ||||
|         var reference = new CryptoKeyReference(request.KeyId, request.Provider); | ||||
|         return new CryptoSigningKey(reference, material.Algorithm, in parameters, material.CreatedAt, request.ExpiresAt, metadata: metadata); | ||||
|     } | ||||
|  | ||||
|     internal static class KmsMetadataKeys | ||||
|     { | ||||
|         public const string Version = "kms.version"; | ||||
|     } | ||||
| } | ||||
| @@ -28,6 +28,7 @@ | ||||
|     <ProjectReference Include="..\StellaOps.Auth.Client\StellaOps.Auth.Client.csproj" /> | ||||
|     <ProjectReference Include="../../../__Libraries/StellaOps.Auth.Security/StellaOps.Auth.Security.csproj" /> | ||||
|     <ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" /> | ||||
|     <ProjectReference Include="../../../__Libraries/StellaOps.Cryptography.Kms/StellaOps.Cryptography.Kms.csproj" /> | ||||
|     <ProjectReference Include="../../../__Libraries/StellaOps.Configuration/StellaOps.Configuration.csproj" /> | ||||
|     <ProjectReference Include="../../../__Libraries/StellaOps.DependencyInjection/StellaOps.DependencyInjection.csproj" /> | ||||
|   </ItemGroup> | ||||
| @@ -36,4 +37,4 @@ | ||||
|       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||||
|     </Content> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
| </Project> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user