feat: Initialize Zastava Webhook service with TLS and Authority authentication
- Added Program.cs to set up the web application with Serilog for logging, health check endpoints, and a placeholder admission endpoint. - Configured Kestrel server to use TLS 1.3 and handle client certificates appropriately. - Created StellaOps.Zastava.Webhook.csproj with necessary dependencies including Serilog and Polly. - Documented tasks in TASKS.md for the Zastava Webhook project, outlining current work and exit criteria for each task.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Zastava.Webhook.Certificates;
|
||||
using StellaOps.Zastava.Webhook.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Tests.Certificates;
|
||||
|
||||
public sealed class SecretFileCertificateSourceTests
|
||||
{
|
||||
[Fact]
|
||||
public void LoadCertificate_FromPemPair_Succeeds()
|
||||
{
|
||||
using var rsa = RSA.Create(2048);
|
||||
var request = new CertificateRequest("CN=zastava-webhook", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
using var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow.AddMinutes(-5), DateTimeOffset.UtcNow.AddHours(1));
|
||||
using var certificateWithKey = certificate.CopyWithPrivateKey(rsa);
|
||||
|
||||
var certificatePath = Path.GetTempFileName();
|
||||
var privateKeyPath = Path.GetTempFileName();
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(certificatePath, certificateWithKey.ExportCertificatePem());
|
||||
using var exportRsa = certificateWithKey.GetRSAPrivateKey() ?? throw new InvalidOperationException("Missing RSA private key");
|
||||
var privateKeyPem = PemEncoding.Write("PRIVATE KEY", exportRsa.ExportPkcs8PrivateKey());
|
||||
File.WriteAllText(privateKeyPath, privateKeyPem);
|
||||
|
||||
var source = new SecretFileCertificateSource(NullLogger<SecretFileCertificateSource>.Instance);
|
||||
var options = new ZastavaWebhookTlsOptions
|
||||
{
|
||||
Mode = ZastavaWebhookTlsMode.Secret,
|
||||
CertificatePath = certificatePath,
|
||||
PrivateKeyPath = privateKeyPath
|
||||
};
|
||||
|
||||
using var loaded = source.LoadCertificate(options);
|
||||
|
||||
Assert.Equal(certificateWithKey.Thumbprint, loaded.Thumbprint);
|
||||
Assert.NotNull(loaded.GetRSAPrivateKey());
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(certificatePath);
|
||||
File.Delete(privateKeyPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoadCertificate_FromPfx_Succeeds()
|
||||
{
|
||||
using var rsa = RSA.Create(2048);
|
||||
var request = new CertificateRequest("CN=zastava-webhook", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
using var certificate = request.CreateSelfSigned(DateTimeOffset.UtcNow.AddMinutes(-5), DateTimeOffset.UtcNow.AddHours(1));
|
||||
using var certificateWithKey = certificate.CopyWithPrivateKey(rsa);
|
||||
|
||||
var pfxPath = Path.GetTempFileName();
|
||||
try
|
||||
{
|
||||
var pfxBytes = certificateWithKey.Export(X509ContentType.Pfx, "test");
|
||||
File.WriteAllBytes(pfxPath, pfxBytes);
|
||||
|
||||
var source = new SecretFileCertificateSource(NullLogger<SecretFileCertificateSource>.Instance);
|
||||
var options = new ZastavaWebhookTlsOptions
|
||||
{
|
||||
Mode = ZastavaWebhookTlsMode.Secret,
|
||||
PfxPath = pfxPath,
|
||||
PfxPassword = "test"
|
||||
};
|
||||
|
||||
using var loaded = source.LoadCertificate(options);
|
||||
Assert.Equal(certificateWithKey.Thumbprint, loaded.Thumbprint);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(pfxPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Zastava.Webhook.Certificates;
|
||||
using StellaOps.Zastava.Webhook.Configuration;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Zastava.Webhook.Tests.Certificates;
|
||||
|
||||
public sealed class WebhookCertificateProviderTests
|
||||
{
|
||||
[Fact]
|
||||
public void Provider_UsesMatchingSource()
|
||||
{
|
||||
var options = Options.Create(new ZastavaWebhookOptions
|
||||
{
|
||||
Tls = new ZastavaWebhookTlsOptions
|
||||
{
|
||||
Mode = ZastavaWebhookTlsMode.Secret,
|
||||
CertificatePath = "/tmp/cert.pem",
|
||||
PrivateKeyPath = "/tmp/key.pem"
|
||||
}
|
||||
});
|
||||
|
||||
var source = new ThrowingCertificateSource();
|
||||
var provider = new WebhookCertificateProvider(options, new[] { source }, NullLogger<WebhookCertificateProvider>.Instance);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => provider.GetCertificate());
|
||||
Assert.True(source.Requested);
|
||||
}
|
||||
|
||||
private sealed class ThrowingCertificateSource : IWebhookCertificateSource
|
||||
{
|
||||
public bool Requested { get; private set; }
|
||||
|
||||
public bool CanHandle(ZastavaWebhookTlsMode mode) => true;
|
||||
|
||||
public System.Security.Cryptography.X509Certificates.X509Certificate2 LoadCertificate(ZastavaWebhookTlsOptions options)
|
||||
{
|
||||
Requested = true;
|
||||
throw new InvalidOperationException("test");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StellaOps.Zastava.Webhook\StellaOps.Zastava.Webhook.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user