mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2025-12-31 04:00:03 +01:00
(feature): sever side agent implementation
This commit is contained in:
parent
5ecc436ddf
commit
6328afd5fb
60
README.md
60
README.md
@ -123,3 +123,63 @@ frontend web
|
||||
backend acme_challenge_backend
|
||||
server acme_challenge 127.0.0.1:8080
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## MaksIT agent
|
||||
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm
|
||||
sudo dnf install -y dotnet-sdk-8.0
|
||||
```
|
||||
|
||||
|
||||
Copy sources to
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/maks-it-agent
|
||||
```
|
||||
|
||||
|
||||
```bash
|
||||
dotnet build --configuration Release
|
||||
dotnet publish -c Release -o /opt/maks-it-agent
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/maks-it-agent.service
|
||||
```
|
||||
|
||||
```bash
|
||||
[Unit]
|
||||
Description=Maks-IT Agent
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=/opt/maks-it-agent
|
||||
ExecStart=/usr/bin/dotnet /opt/maks-it-agent/Agent.dll --urls "http://*:5000"
|
||||
Restart=always
|
||||
# Restart service after 10 seconds if the dotnet service crashes:
|
||||
RestartSec=10
|
||||
KillSignal=SIGINT
|
||||
SyslogIdentifier=dotnet-servicereloader
|
||||
User=root
|
||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now maks-it-agent.service
|
||||
sudo systemctl status maks-it-agent.service
|
||||
```
|
||||
|
||||
23
src/Agent/Agent.csproj
Normal file
23
src/Agent/Agent.csproj
Normal file
@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Models\Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="build_and_deploy.sh">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
6
src/Agent/Configuration.cs
Normal file
6
src/Agent/Configuration.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace MaksIT.Agent {
|
||||
public class Configuration {
|
||||
public required string ApiKey { get; set; }
|
||||
public required string CertsPath { get; set; }
|
||||
}
|
||||
}
|
||||
41
src/Agent/Controllers/CertsController.cs
Normal file
41
src/Agent/Controllers/CertsController.cs
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using MaksIT.Models.Agent.Requests;
|
||||
|
||||
namespace MaksIT.Agent.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class CertsController : ControllerBase {
|
||||
|
||||
private readonly Configuration _appSettings;
|
||||
|
||||
public CertsController(
|
||||
IOptions<Configuration> appSettings
|
||||
) {
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public IActionResult Upload([FromBody] CertsUploadRequest requestData) {
|
||||
if (!Request.Headers.TryGetValue("X-API-KEY", out var extractedApiKey)) {
|
||||
return Unauthorized("API Key is missing");
|
||||
}
|
||||
|
||||
if (!_appSettings.ApiKey.Equals(extractedApiKey)) {
|
||||
return Unauthorized("Unauthorized client");
|
||||
}
|
||||
|
||||
foreach (var (fileName, fileContent) in requestData.Certs) {
|
||||
System.IO.File.WriteAllText(Path.Combine(_appSettings.CertsPath, fileName), fileContent);
|
||||
}
|
||||
|
||||
return Ok("Certificates uploaded successfully");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
14
src/Agent/Controllers/HelloWorldController.cs
Normal file
14
src/Agent/Controllers/HelloWorldController.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Agent.Controllers {
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class HelloWorldController : ControllerBase {
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Get() {
|
||||
return Ok("Hello, World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
61
src/Agent/Controllers/ServiceController.cs
Normal file
61
src/Agent/Controllers/ServiceController.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System.Diagnostics;
|
||||
using MaksIT.Models.Agent.Requests;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace MaksIT.Agent.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class ServiceController : ControllerBase {
|
||||
|
||||
private readonly Configuration _appSettings;
|
||||
|
||||
public ServiceController(
|
||||
IOptions<Configuration> appSettings
|
||||
) {
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public IActionResult Reload([FromBody] ServiceReloadRequest requestData) {
|
||||
var serviceName = requestData.ServiceName;
|
||||
|
||||
if (!Request.Headers.TryGetValue("X-API-KEY", out var extractedApiKey)) {
|
||||
return Unauthorized("API Key is missing");
|
||||
}
|
||||
|
||||
if (!_appSettings.ApiKey.Equals(extractedApiKey)) {
|
||||
return Unauthorized("Unauthorized client");
|
||||
}
|
||||
|
||||
try {
|
||||
var processStartInfo = new ProcessStartInfo {
|
||||
FileName = "/bin/systemctl",
|
||||
Arguments = $"reload {serviceName}",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
using (var process = new Process { StartInfo = processStartInfo }) {
|
||||
process.Start();
|
||||
process.WaitForExit();
|
||||
|
||||
var output = process.StandardOutput.ReadToEnd();
|
||||
var error = process.StandardError.ReadToEnd();
|
||||
|
||||
if (process.ExitCode != 0) {
|
||||
return StatusCode(500, $"Error reloading service: {error}");
|
||||
}
|
||||
|
||||
return Ok($"Service {serviceName} reloaded successfully: {output}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return StatusCode(500, $"Exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
src/Agent/Program.cs
Normal file
34
src/Agent/Program.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using MaksIT.Agent;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Extract configuration
|
||||
var configuration = builder.Configuration;
|
||||
|
||||
// Configure strongly typed settings objects
|
||||
var configurationSection = configuration.GetSection("Configuration");
|
||||
var appSettings = configurationSection.Get<Configuration>() ?? throw new ArgumentNullException();
|
||||
|
||||
// Allow configurations to be available through IOptions<Configuration>
|
||||
builder.Services.Configure<Configuration>(configurationSection);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment()) {
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
31
src/Agent/Properties/launchSettings.json
Normal file
31
src/Agent/Properties/launchSettings.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:7748",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/Agent/ServiceReloader.http
Normal file
6
src/Agent/ServiceReloader.http
Normal file
@ -0,0 +1,6 @@
|
||||
@ServiceReloader_HostAddress = http://localhost:5186
|
||||
|
||||
GET {{ServiceReloader_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
8
src/Agent/appsettings.Development.json
Normal file
8
src/Agent/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Agent/appsettings.json
Normal file
14
src/Agent/appsettings.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"Configuration": {
|
||||
"ApiKey": "UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=",
|
||||
"CertsPath": "/etc/haproxy/certs"
|
||||
}
|
||||
}
|
||||
77
src/Agent/build_and_deploy.sh
Normal file
77
src/Agent/build_and_deploy.sh
Normal file
@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Variables
|
||||
SERVICE_NAME="maks-it-agent"
|
||||
SERVICE_PORT="5000"
|
||||
SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service"
|
||||
INSTALL_DIR="/opt/$SERVICE_NAME"
|
||||
DOTNET_EXEC="/usr/bin/dotnet"
|
||||
EXEC_CMD="$DOTNET_EXEC $INSTALL_DIR/Agent.dll --urls \"http://*:$SERVICE_PORT\""
|
||||
APPSETTINGS_FILE="appsettings.json"
|
||||
NO_NEW_KEY_FLAG="--no-new-key"
|
||||
|
||||
# Update package index and install the Microsoft package repository
|
||||
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm
|
||||
sudo dnf install -y dotnet-sdk-8.0
|
||||
|
||||
# Check if the service exists and stop it if it does
|
||||
if systemctl list-units --full -all | grep -Fq "$SERVICE_NAME.service"; then
|
||||
sudo systemctl stop $SERVICE_NAME.service
|
||||
sudo systemctl disable $SERVICE_NAME.service
|
||||
sudo rm -f $SERVICE_FILE
|
||||
fi
|
||||
|
||||
# Clean up the old files if they exist
|
||||
sudo rm -rf $INSTALL_DIR
|
||||
|
||||
# Create the application directory
|
||||
sudo mkdir -p $INSTALL_DIR
|
||||
|
||||
# Update appsettings.json if --no-new-key flag is not provided
|
||||
if [[ "$1" != "$NO_NEW_KEY_FLAG" ]]; then
|
||||
NEW_API_KEY=$(openssl rand -base64 32)
|
||||
jq --arg newApiKey "$NEW_API_KEY" '.Configuration.ApiKey = $newApiKey' $APPSETTINGS_FILE > tmp.$$.json && mv tmp.$$.json $APPSETTINGS_FILE
|
||||
fi
|
||||
|
||||
# Build and publish the .NET application
|
||||
sudo dotnet build --configuration Release
|
||||
sudo dotnet publish -c Release -o $INSTALL_DIR
|
||||
|
||||
# Create the systemd service unit file
|
||||
sudo bash -c "cat > $SERVICE_FILE <<EOL
|
||||
[Unit]
|
||||
Description=Maks-IT Agent
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
WorkingDirectory=$INSTALL_DIR
|
||||
ExecStart=$EXEC_CMD
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
KillSignal=SIGINT
|
||||
SyslogIdentifier=dotnet-servicereloader
|
||||
User=root
|
||||
Environment=ASPNETCORE_ENVIRONMENT=Production
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL"
|
||||
|
||||
# Reload systemd to recognize the new service, enable it to start on boot, and start the service now
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now $SERVICE_NAME.service
|
||||
|
||||
# Create the firewall service rule
|
||||
echo '<?xml version="1.0" encoding="utf-8"?>
|
||||
<service>
|
||||
<short>Maks-IT Agent</short>
|
||||
<port protocol="tcp" port="'$SERVICE_PORT'"/>
|
||||
</service>' > /etc/firewalld/services/maks-it-agent.xml
|
||||
|
||||
sleep 10
|
||||
|
||||
# Add the services to the firewall
|
||||
firewall-cmd --permanent --add-service=maks-it-agent
|
||||
|
||||
# Reload the firewall
|
||||
firewall-cmd --reload
|
||||
@ -15,10 +15,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3374FDB1
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SSHProviderTests", "Tests\SSHSerivceTests\SSHProviderTests.csproj", "{3937760A-FFB3-4A8C-ABD1-CDDCE1D977C4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LetsEncryptServer", "LetsEncryptServer\LetsEncryptServer.csproj", "{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetsEncryptServer", "LetsEncryptServer\LetsEncryptServer.csproj", "{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}"
|
||||
EndProject
|
||||
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{0233E43F-435D-4309-B20C-ECD4BFBD2E63}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Agent", "Agent\Agent.csproj", "{871BDED3-C6AE-437D-9B45-3AA3F184D002}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "Models\Models.csproj", "{6814169B-D4D0-40B2-9FA9-89997DD44C30}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -53,6 +57,14 @@ Global
|
||||
{0233E43F-435D-4309-B20C-ECD4BFBD2E63}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0233E43F-435D-4309-B20C-ECD4BFBD2E63}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0233E43F-435D-4309-B20C-ECD4BFBD2E63}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{871BDED3-C6AE-437D-9B45-3AA3F184D002}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{871BDED3-C6AE-437D-9B45-3AA3F184D002}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{871BDED3-C6AE-437D-9B45-3AA3F184D002}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{871BDED3-C6AE-437D-9B45-3AA3F184D002}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6814169B-D4D0-40B2-9FA9-89997DD44C30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@ -1,20 +1,17 @@
|
||||
namespace MaksIT.LetsEncryptServer {
|
||||
|
||||
public class Server {
|
||||
public required string Ip { get; set; }
|
||||
public required int SocketPort { get; set; }
|
||||
public required int SSHPort { get; set; }
|
||||
public required string Path { get; set; }
|
||||
public class Agent {
|
||||
public required string AgentHostname { get; set; }
|
||||
public required int AgentPort { get; set; }
|
||||
public required string AgentKey { get; set; }
|
||||
|
||||
public required string Username { get; set; }
|
||||
public string? Password { get; set; }
|
||||
public string[]? PrivateKeys { get; set; }
|
||||
public required string ServiceToReload { get; set; }
|
||||
}
|
||||
|
||||
public class Configuration {
|
||||
public required string Production { get; set; }
|
||||
public required string Staging { get; set; }
|
||||
public required bool DevMode { get; set; }
|
||||
public required Server Server { get; set; }
|
||||
public required Agent Agent { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ using Microsoft.Extensions.Options;
|
||||
|
||||
using DomainResults.Mvc;
|
||||
|
||||
using MaksIT.LetsEncryptServer.Models.Requests;
|
||||
using MaksIT.LetsEncryptServer.Services;
|
||||
using MaksIT.Models.LetsEncryptServer.Requests;
|
||||
|
||||
|
||||
namespace MaksIT.LetsEncryptServer.Controllers;
|
||||
@ -107,8 +107,8 @@ public class CertsFlowController : ControllerBase {
|
||||
/// <param name="requestData"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("[action]/{sessionId}")]
|
||||
public IActionResult ApplyCertificates(Guid sessionId, [FromBody] GetCertificatesRequest requestData) {
|
||||
var result = _certsFlowService.ApplyCertificates(sessionId, requestData);
|
||||
public async Task<IActionResult> ApplyCertificates(Guid sessionId, [FromBody] GetCertificatesRequest requestData) {
|
||||
var result = await _certsFlowService.ApplyCertificates(sessionId, requestData);
|
||||
return result.ToActionResult();
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,11 +17,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LetsEncrypt\LetsEncrypt.csproj" />
|
||||
<ProjectReference Include="..\SSHProvider\SSHProvider.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\Responses\" />
|
||||
<ProjectReference Include="..\Models\Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -28,6 +28,7 @@ builder.Services.AddMemoryCache();
|
||||
builder.Services.AddHttpClient<ILetsEncryptService, LetsEncryptService>();
|
||||
builder.Services.AddScoped<ICertsFlowService, CertsFlowService>();
|
||||
builder.Services.AddSingleton<ICacheService, CacheService>();
|
||||
builder.Services.AddHttpClient<IAgentService, AgentService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
||||
72
src/LetsEncryptServer/Services/AgentService.cs
Normal file
72
src/LetsEncryptServer/Services/AgentService.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using DomainResults.Common;
|
||||
using MaksIT.Models.Agent.Requests;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MaksIT.LetsEncryptServer.Services {
|
||||
|
||||
public interface IAgentService {
|
||||
Task<IDomainResult> GetHelloWorld();
|
||||
Task<IDomainResult> UploadCerts(Dictionary<string, string> certs);
|
||||
Task<IDomainResult> ReloadService(string serviceName);
|
||||
}
|
||||
|
||||
public class AgentService : IAgentService {
|
||||
|
||||
private readonly Configuration _appSettings;
|
||||
private readonly ILogger<AgentService> _logger;
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public AgentService(
|
||||
IOptions<Configuration> appSettings,
|
||||
ILogger<AgentService> logger,
|
||||
HttpClient httpClient
|
||||
) {
|
||||
_appSettings = appSettings.Value;
|
||||
_logger = logger;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public Task<IDomainResult> GetHelloWorld() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<IDomainResult> ReloadService(string serviceName) {
|
||||
var requestBody = new ServiceReloadRequest { ServiceName = serviceName };
|
||||
var endpoint = $"/Service/Reload";
|
||||
return await SendHttpRequest(requestBody, endpoint);
|
||||
}
|
||||
|
||||
public async Task<IDomainResult> UploadCerts(Dictionary<string, string> certs) {
|
||||
var requestBody = new CertsUploadRequest { Certs = certs };
|
||||
var endpoint = $"/Certs/Upload";
|
||||
return await SendHttpRequest(requestBody, endpoint);
|
||||
}
|
||||
|
||||
private async Task<IDomainResult> SendHttpRequest<T>(T requestBody, string endpoint) {
|
||||
try {
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, $"{_appSettings.Agent.AgentHostname}:{_appSettings.Agent.AgentPort}{endpoint}") {
|
||||
Content = new StringContent(JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
request.Headers.Add("x-api-key", _appSettings.Agent.AgentKey);
|
||||
request.Headers.Add("accept", "application/json");
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
|
||||
if (response.IsSuccessStatusCode) {
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
else {
|
||||
_logger.LogError($"Request to {endpoint} failed with status code: {response.StatusCode}");
|
||||
return IDomainResult.Failed($"Request to {endpoint} failed with status code: {response.StatusCode}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
_logger.LogError(ex, "Something went wrong");
|
||||
return IDomainResult.Failed("Something went wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,8 +6,7 @@ using DomainResults.Common;
|
||||
|
||||
using MaksIT.LetsEncrypt.Entities;
|
||||
using MaksIT.LetsEncrypt.Services;
|
||||
using MaksIT.LetsEncryptServer.Models.Requests;
|
||||
using MaksIT.SSHProvider;
|
||||
using MaksIT.Models.LetsEncryptServer.Requests;
|
||||
|
||||
|
||||
namespace MaksIT.LetsEncryptServer.Services;
|
||||
@ -24,7 +23,7 @@ public interface ICertsFlowService : ICertsFlowServiceBase {
|
||||
Task<IDomainResult> CompleteChallengesAsync(Guid sessionId);
|
||||
Task<IDomainResult> GetOrderAsync(Guid sessionId, GetOrderRequest requestData);
|
||||
Task<IDomainResult> GetCertificatesAsync(Guid sessionId, GetCertificatesRequest requestData);
|
||||
(Dictionary<string, string>?, IDomainResult) ApplyCertificates(Guid sessionId, GetCertificatesRequest requestData);
|
||||
Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificates(Guid sessionId, GetCertificatesRequest requestData);
|
||||
}
|
||||
|
||||
public class CertsFlowService : ICertsFlowService {
|
||||
@ -33,6 +32,7 @@ public class CertsFlowService : ICertsFlowService {
|
||||
private readonly ILogger<CertsFlowService> _logger;
|
||||
private readonly ILetsEncryptService _letsEncryptService;
|
||||
private readonly ICacheService _cacheService;
|
||||
private readonly IAgentService _agentService;
|
||||
|
||||
private readonly string _acmePath;
|
||||
|
||||
@ -40,12 +40,14 @@ public class CertsFlowService : ICertsFlowService {
|
||||
IOptions<Configuration> appSettings,
|
||||
ILogger<CertsFlowService> logger,
|
||||
ILetsEncryptService letsEncryptService,
|
||||
ICacheService cashService
|
||||
ICacheService cashService,
|
||||
IAgentService agentService
|
||||
) {
|
||||
_appSettings = appSettings.Value;
|
||||
_logger = logger;
|
||||
_letsEncryptService = letsEncryptService;
|
||||
_cacheService = cashService;
|
||||
_agentService = agentService;
|
||||
|
||||
_acmePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "acme");
|
||||
if (!Directory.Exists(_acmePath))
|
||||
@ -138,7 +140,7 @@ public class CertsFlowService : ICertsFlowService {
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
|
||||
public (Dictionary<string, string>?, IDomainResult) ApplyCertificates(Guid sessionId, GetCertificatesRequest requestData) {
|
||||
public async Task<(Dictionary<string, string>?, IDomainResult)> ApplyCertificates(Guid sessionId, GetCertificatesRequest requestData) {
|
||||
var results = new Dictionary<string, string>();
|
||||
|
||||
foreach (var subject in requestData.Hostnames) {
|
||||
@ -150,16 +152,13 @@ public class CertsFlowService : ICertsFlowService {
|
||||
results.Add(subject, content);
|
||||
}
|
||||
|
||||
var uploadResult = UploadToServer(results);
|
||||
if (!uploadResult.IsSuccess)
|
||||
// TODO: send the certificates to the server
|
||||
var uploadResult = await _agentService.UploadCerts(results);
|
||||
if(!uploadResult.IsSuccess)
|
||||
return (null, uploadResult);
|
||||
|
||||
//var notifyResult = NotifyHaproxy(results);
|
||||
//if (!notifyResult.IsSuccess)
|
||||
// return (null, notifyResult);
|
||||
|
||||
var reloadResult = ReloadServer();
|
||||
if (!reloadResult.IsSuccess)
|
||||
var reloadResult = await _agentService.ReloadService(_appSettings.Agent.ServiceToReload);
|
||||
if(!reloadResult.IsSuccess)
|
||||
return (null, reloadResult);
|
||||
|
||||
return IDomainResult.Success(results);
|
||||
@ -175,129 +174,6 @@ public class CertsFlowService : ICertsFlowService {
|
||||
return IDomainResult.Success(fileContent);
|
||||
}
|
||||
|
||||
private IDomainResult UploadToServer(Dictionary<string, string> results) {
|
||||
var server = _appSettings.Server;
|
||||
|
||||
try {
|
||||
using (SSHService sshClient = (server.PrivateKeys != null && server.PrivateKeys.Any(x => !string.IsNullOrWhiteSpace(x)))
|
||||
? new SSHService(_logger, server.Ip, server.SSHPort, server.Username, server.PrivateKeys)
|
||||
: !string.IsNullOrWhiteSpace(server.Password)
|
||||
? new SSHService(_logger, server.Ip, server.SSHPort, server.Username, server.Password)
|
||||
: throw new ArgumentNullException("Neither private keys nor password was provided")) {
|
||||
|
||||
var sshConnectResult = sshClient.Connect();
|
||||
if (!sshConnectResult.IsSuccess)
|
||||
return sshConnectResult;
|
||||
|
||||
foreach (var result in results) {
|
||||
var uploadResult = sshClient.Upload(server.Path, result.Key, Encoding.UTF8.GetBytes(result.Value));
|
||||
if (!uploadResult.IsSuccess)
|
||||
return uploadResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
var message = "Unable to upload files to remote server";
|
||||
_logger.LogError(ex, message);
|
||||
|
||||
return IDomainResult.CriticalDependencyError(message);
|
||||
}
|
||||
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
private IDomainResult ReloadServer() {
|
||||
var server = _appSettings.Server;
|
||||
|
||||
try {
|
||||
using (SSHService sshClient = (server.PrivateKeys != null && server.PrivateKeys.Any(x => !string.IsNullOrWhiteSpace(x)))
|
||||
? new SSHService(_logger, server.Ip, server.SSHPort, server.Username, server.PrivateKeys)
|
||||
: !string.IsNullOrWhiteSpace(server.Password)
|
||||
? new SSHService(_logger, server.Ip, server.SSHPort, server.Username, server.Password)
|
||||
: throw new ArgumentNullException("Neither private keys nor password was provided")) {
|
||||
|
||||
var sshConnectResult = sshClient.Connect();
|
||||
if (!sshConnectResult.IsSuccess)
|
||||
return sshConnectResult;
|
||||
|
||||
// TODO: Prefer to create the native linux service which can receive the signal to reload the services
|
||||
return sshClient.RunSudoCommand("", "systemctl reload haproxy");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
var message = "Unable to upload files to remote server";
|
||||
_logger.LogError(ex, message);
|
||||
|
||||
return IDomainResult.CriticalDependencyError(message);
|
||||
}
|
||||
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Currently not working
|
||||
/// </summary>
|
||||
/// <param name="results"></param>
|
||||
/// <returns></returns>
|
||||
private IDomainResult NotifyHaproxy(Dictionary<string, string> results) {
|
||||
var server = _appSettings.Server;
|
||||
|
||||
try {
|
||||
using (var client = new TcpClient(server.Ip, server.SocketPort))
|
||||
using (var networkStream = client.GetStream())
|
||||
using (var writer = new StreamWriter(networkStream, Encoding.ASCII))
|
||||
using (var reader = new StreamReader(networkStream, Encoding.ASCII)) {
|
||||
writer.AutoFlush = true;
|
||||
|
||||
foreach (var result in results) {
|
||||
var certFile = result.Key;
|
||||
|
||||
// Prepare the certificate
|
||||
string prepareCommand = $"new ssl cert {server.Path}/{certFile}";
|
||||
writer.WriteLine(prepareCommand);
|
||||
writer.Flush();
|
||||
string prepareResponse = reader.ReadLine();
|
||||
//if (prepareResponse.Contains("error", StringComparison.OrdinalIgnoreCase)) {
|
||||
// _logger.LogError($"Error while preparing certificate {certFile}: {prepareResponse}");
|
||||
// return IDomainResult.CriticalDependencyError($"Error while preparing certificate {certFile}");
|
||||
//}
|
||||
|
||||
// Set the certificate
|
||||
string setCommand = $"set ssl cert {server.Path}/{certFile} <<\n{result.Value}\n";
|
||||
writer.WriteLine(setCommand);
|
||||
writer.Flush();
|
||||
string setResponse = reader.ReadLine();
|
||||
//if (setResponse.Contains("error", StringComparison.OrdinalIgnoreCase)) {
|
||||
// _logger.LogError($"Error while setting certificate {certFile}: {setResponse}");
|
||||
// return IDomainResult.CriticalDependencyError($"Error while setting certificate {certFile}");
|
||||
//}
|
||||
|
||||
// Commit the certificate
|
||||
string commitCommand = $"commit ssl cert {server.Path}/{certFile}";
|
||||
writer.WriteLine(commitCommand);
|
||||
writer.Flush();
|
||||
string commitResponse = reader.ReadLine();
|
||||
//if (commitResponse.Contains("error", StringComparison.OrdinalIgnoreCase)) {
|
||||
// _logger.LogError($"Error while committing certificate {certFile}: {commitResponse}");
|
||||
// return IDomainResult.CriticalDependencyError($"Error while committing certificate {certFile}");
|
||||
//}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Certificates committed successfully.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
var message = "An error occurred while committing certificates";
|
||||
_logger.LogError(ex, message);
|
||||
|
||||
return IDomainResult.CriticalDependencyError(message);
|
||||
}
|
||||
|
||||
return IDomainResult.Success();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void DeleteExporedChallenges() {
|
||||
var currentDate = DateTime.Now;
|
||||
|
||||
|
||||
@ -13,14 +13,12 @@
|
||||
|
||||
"DevMode": true,
|
||||
|
||||
"Server": {
|
||||
"Ip": "192.168.1.4",
|
||||
"SocketPort": 9999,
|
||||
"SSHPort": 22,
|
||||
"Path": "/etc/haproxy/certs",
|
||||
"Username": "acme",
|
||||
"PrivateKeys": [],
|
||||
"Password": "acme"
|
||||
"Agent": {
|
||||
"AgentHostname": "http://lblsrv0001.corp.maks-it.com",
|
||||
"AgentPort": 5000,
|
||||
"AgentKey": "UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=",
|
||||
|
||||
"ServiceToReload": "haproxy"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Models/Agent/Requests/CertsUploadRequest.cs
Normal file
7
src/Models/Agent/Requests/CertsUploadRequest.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace MaksIT.Models.Agent.Requests {
|
||||
public class CertsUploadRequest {
|
||||
|
||||
public Dictionary<string, string> Certs { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
11
src/Models/Agent/Requests/ServiceReloadRequest.cs
Normal file
11
src/Models/Agent/Requests/ServiceReloadRequest.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MaksIT.Models.Agent.Requests {
|
||||
public class ServiceReloadRequest {
|
||||
public string ServiceName { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
namespace MaksIT.LetsEncryptServer.Models.Requests {
|
||||
namespace MaksIT.Models.LetsEncryptServer.Requests {
|
||||
public class GetCertificatesRequest {
|
||||
public string[] Hostnames { get; set; }
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
namespace MaksIT.LetsEncryptServer.Models.Requests {
|
||||
namespace MaksIT.Models.LetsEncryptServer.Requests {
|
||||
public class GetOrderRequest {
|
||||
public string[] Hostnames { get; set; }
|
||||
}
|
||||
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MaksIT.LetsEncryptServer.Models.Requests {
|
||||
namespace MaksIT.Models.LetsEncryptServer.Requests {
|
||||
public class InitRequest {
|
||||
public string[] Contacts { get; set; }
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
namespace MaksIT.LetsEncryptServer.Models.Requests {
|
||||
namespace MaksIT.Models.LetsEncryptServer.Requests {
|
||||
public class NewOrderRequest {
|
||||
public string[] Hostnames { get; set; }
|
||||
|
||||
14
src/Models/Models.csproj
Normal file
14
src/Models/Models.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Agent\Responses\" />
|
||||
<Folder Include="LetsEncryptServer\Responses\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
479
src/Postman/LetsEncrypt Production.postman_collection.json
Normal file
479
src/Postman/LetsEncrypt Production.postman_collection.json
Normal file
@ -0,0 +1,479 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "728f64b6-893b-43fa-802e-ee836d1dc372",
|
||||
"name": "LetsEncrypt Production",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "33635244"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "letsencrypt production",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "https://acme-v02.api.letsencrypt.org/directory",
|
||||
"protocol": "https",
|
||||
"host": [
|
||||
"acme-v02",
|
||||
"api",
|
||||
"letsencrypt",
|
||||
"org"
|
||||
],
|
||||
"path": [
|
||||
"directory"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "configure client",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"// Ensure the response status code is 200 (OK)\r",
|
||||
"if (pm.response.code === 200) {\r",
|
||||
" // Get the plain text response\r",
|
||||
" let responseBody = pm.response.text();\r",
|
||||
" \r",
|
||||
" // Remove the surrounding quotes if present\r",
|
||||
" responseBody = responseBody.replace(/^\"|\"$/g, '');\r",
|
||||
" \r",
|
||||
" // Check if the response body is a valid GUID\r",
|
||||
" if (/^[0-9a-fA-F-]{36}$/.test(responseBody)) {\r",
|
||||
" // Set the environment variable sessionId with the response\r",
|
||||
" pm.environment.set(\"sessionId\", responseBody);\r",
|
||||
" console.log(`sessionId set to: ${responseBody}`);\r",
|
||||
" } else {\r",
|
||||
" console.log(\"Response body is not a valid GUID\");\r",
|
||||
" }\r",
|
||||
"} else {\r",
|
||||
" console.log(`Request failed with status code: ${pm.response.code}`);\r",
|
||||
"}\r",
|
||||
""
|
||||
],
|
||||
"type": "text/javascript",
|
||||
"packages": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/ConfigureClient",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"ConfigureClient"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "terms of service",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/TermsOfService/{{sessionId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"TermsOfService",
|
||||
"{{sessionId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "init",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"// Ensure the response status code is 200 (OK)\r",
|
||||
"if (pm.response.code === 200) {\r",
|
||||
" // Get the plain text response\r",
|
||||
" let responseBody = pm.response.text();\r",
|
||||
" \r",
|
||||
" // Remove the surrounding quotes if present\r",
|
||||
" responseBody = responseBody.replace(/^\"|\"$/g, '');\r",
|
||||
" \r",
|
||||
" // Check if the response body is a valid GUID\r",
|
||||
" if (/^[0-9a-fA-F-]{36}$/.test(responseBody)) {\r",
|
||||
" // Set the environment variable accountId with the response\r",
|
||||
" pm.environment.set(\"accountId\", responseBody);\r",
|
||||
" console.log(`accountId set to: ${responseBody}`);\r",
|
||||
" } else {\r",
|
||||
" console.log(\"Response body is not a valid GUID\");\r",
|
||||
" }\r",
|
||||
"} else {\r",
|
||||
" console.log(`Request failed with status code: ${pm.response.code}`);\r",
|
||||
"}\r",
|
||||
""
|
||||
],
|
||||
"type": "text/javascript",
|
||||
"packages": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "prerequest",
|
||||
"script": {
|
||||
"exec": [
|
||||
"// Retrieve sessionId and accountId from environment variables or global variables\r",
|
||||
"var sessionId = pm.environment.get(\"sessionId\") || pm.globals.get(\"sessionId\");\r",
|
||||
"var accountId = pm.environment.get(\"accountId\") || pm.globals.get(\"accountId\");\r",
|
||||
"\r",
|
||||
"// Base URL without the optional accountId parameter\r",
|
||||
"var baseUrl = `http://localhost:8080/CertsFlow/Init/${sessionId}`;\r",
|
||||
"\r",
|
||||
"// Append the accountId if it is provided\r",
|
||||
"if (accountId) {\r",
|
||||
" pm.request.url = `${baseUrl}/${accountId}`;\r",
|
||||
"} else {\r",
|
||||
" pm.request.url = baseUrl;\r",
|
||||
"}"
|
||||
],
|
||||
"type": "text/javascript",
|
||||
"packages": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"contacts\": [\r\n \"maksym.sadovnychyy@gmail.com\"\r\n ]\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/Init/{{sessionId}}/{{accountId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"Init",
|
||||
"{{sessionId}}",
|
||||
"{{accountId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "new order",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"// Ensure the response status code is 200 (OK)\r",
|
||||
"if (pm.response.code === 200) {\r",
|
||||
" // Parse the JSON response\r",
|
||||
" let responseBody;\r",
|
||||
" try {\r",
|
||||
" responseBody = pm.response.json();\r",
|
||||
" } catch (e) {\r",
|
||||
" console.error(\"Failed to parse JSON response:\", e);\r",
|
||||
" return;\r",
|
||||
" }\r",
|
||||
"\r",
|
||||
" // Check if the response is an array and has at least one element\r",
|
||||
" if (Array.isArray(responseBody) && responseBody.length > 0) {\r",
|
||||
" // Get the first element of the array\r",
|
||||
" const firstElement = responseBody[0];\r",
|
||||
" \r",
|
||||
" // Set the environment variable challenge with the first element\r",
|
||||
" pm.environment.set(\"challenge\", firstElement);\r",
|
||||
" console.log(`challenge set to: ${firstElement}`);\r",
|
||||
" } else {\r",
|
||||
" console.log(\"Response body is not an array or is empty\");\r",
|
||||
" }\r",
|
||||
"} else {\r",
|
||||
" console.log(`Request failed with status code: ${pm.response.code}`);\r",
|
||||
"}\r",
|
||||
""
|
||||
],
|
||||
"type": "text/javascript",
|
||||
"packages": {}
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ],\r\n \"challengeType\": \"http-01\"\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/NewOrder/{{sessionId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"NewOrder",
|
||||
"{{sessionId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "acme-challenge local",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/.well-known/acme-challenge/{{challenge}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
".well-known",
|
||||
"acme-challenge",
|
||||
"{{challenge}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "acme-challenge",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://maks-it.com/.well-known/acme-challenge/{{challenge}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"maks-it",
|
||||
"com"
|
||||
],
|
||||
"path": [
|
||||
".well-known",
|
||||
"acme-challenge",
|
||||
"{{challenge}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "complete challenges",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/CompleteChallenges/{{sessionId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"CompleteChallenges",
|
||||
"{{sessionId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "get order",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ]\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/GetOrder/{{sessionId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"GetOrder",
|
||||
"{{sessionId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "get certificates",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ]\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/GetCertificates/{{sessionId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"GetCertificates",
|
||||
"{{sessionId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "apply certificates",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"hostnames\": [\r\n \"maks-it.com\",\r\n \"auth.maks-it.com\"\r\n ]\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:8080/CertsFlow/ApplyCertificates/{{sessionId}}",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8080",
|
||||
"path": [
|
||||
"CertsFlow",
|
||||
"ApplyCertificates",
|
||||
"{{sessionId}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "728f64b6-893b-43fa-802e-ee836d1dc372",
|
||||
"name": "LetsEncrypt",
|
||||
"_postman_id": "95186b61-1197-4a6e-a90f-d97223528d90",
|
||||
"name": "LetsEncrypt Staging",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "33635244"
|
||||
},
|
||||
@ -28,27 +28,6 @@
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "letsencrypt production",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "https://acme-v02.api.letsencrypt.org/directory",
|
||||
"protocol": "https",
|
||||
"host": [
|
||||
"acme-v02",
|
||||
"api",
|
||||
"letsencrypt",
|
||||
"org"
|
||||
],
|
||||
"path": [
|
||||
"directory"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "configure client",
|
||||
"event": [
|
||||
77
src/Postman/Maks-IT Agent.postman_collection.json
Normal file
77
src/Postman/Maks-IT Agent.postman_collection.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "1e13f461-ccaa-436a-92e4-e14c05131b96",
|
||||
"name": "Maks-IT Agent",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"_exporter_id": "33635244"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "reload service",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "x-api-key",
|
||||
"value": "{{agentKey}}"
|
||||
},
|
||||
{
|
||||
"key": "Accept",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\r\n \"serviceName\": {{serviceName}}\r\n}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://lblsrv0001.corp.maks-it.com:5000/Service/Reload",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"lblsrv0001",
|
||||
"corp",
|
||||
"maks-it",
|
||||
"com"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"Service",
|
||||
"Reload"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
},
|
||||
{
|
||||
"name": "hello world",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://lblsrv0001.corp.maks-it.com:5000/HelloWorld",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"lblsrv0001",
|
||||
"corp",
|
||||
"maks-it",
|
||||
"com"
|
||||
],
|
||||
"port": "5000",
|
||||
"path": [
|
||||
"HelloWorld"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user