(feature): first release

This commit is contained in:
Maksym Sadovnychyy 2024-08-11 18:26:49 +02:00
parent 6d10e3af53
commit b30d7903a5
20 changed files with 431 additions and 174 deletions

200
README.md
View File

@ -7,82 +7,36 @@ Simple client to obtain Let's Encrypt HTTPS certificates developed with .net cor
* 29 Jun, 2019 - V1.0 * 29 Jun, 2019 - V1.0
* 01 Nov, 2019 - V2.0 (Dependency Injection pattern impelemtation) * 01 Nov, 2019 - V2.0 (Dependency Injection pattern impelemtation)
* 31 May, 2024 - V3.0 (Webapi and containerization) * 31 May, 2024 - V3.0 (Webapi and containerization)
* 11 Aug, 2024 - V3.1 (Release)
## Haproxy configuration ## Haproxy configuration
```bash
# Create the user with a normal shell
sudo useradd -m -s /bin/bash acme
# Set the user's password
sudo passwd acme
```
```bash
sudo passwd acme
```
```bash ```bash
sudo mkdir /etc/haproxy/certs sudo mkdir /etc/haproxy/certs
chown acme:root /etc/haproxy/certs
``` ```
```bash ```bash
#--------------------------------------------------------------------- sudo nano /etc/haproxy/haproxy.cfg
# Example configuration for a possible web application. See the ```
# full configuration options online.
#
# https://www.haproxy.org/download/1.8/doc/configuration.txt
#
#---------------------------------------------------------------------
```ini
#--------------------------------------------------------------------- #---------------------------------------------------------------------
# Global settings # Global settings
#--------------------------------------------------------------------- #---------------------------------------------------------------------
global global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2 log 127.0.0.1 local2
chroot /var/lib/haproxy chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid pidfile /var/run/haproxy.pid
maxconn 4000 maxconn 4000
user haproxy user haproxy
group haproxy group haproxy
daemon daemon
stats socket /var/lib/haproxy/stats
# Adjust the maxconn value based on your server\'s capacity
maxconn 2048
# SSL certificates directory
# ca-base /etc/ssl/certs
#crt-base /etc/ssl/private
# Default SSL certificate (used if no SNI match)
#ssl-default-bind-crt /etc/haproxy/certs/default.pem
# turn on stats unix socket
# stats socket /var/lib/haproxy/stats level admin mode 660
#stats socket /var/run/haproxy/admin.sock level admin mode 660 user haproxy group haproxy
# utilize system-wide crypto-policies
ssl-default-bind-ciphers PROFILE=SYSTEM ssl-default-bind-ciphers PROFILE=SYSTEM
ssl-default-server-ciphers PROFILE=SYSTEM ssl-default-server-ciphers PROFILE=SYSTEM
#--------------------------------------------------------------------- #---------------------------------------------------------------------
# common defaults that all the \'listen\' and \'backend\' sections will # common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block # use if not designated in their block
#--------------------------------------------------------------------- #---------------------------------------------------------------------
defaults defaults
@ -103,83 +57,111 @@ defaults
timeout check 10s timeout check 10s
maxconn 3000 maxconn 3000
#---------------------------------------------------------------------
# Frontend for HTTP traffic on port 80
#---------------------------------------------------------------------
frontend http_frontend
bind *:80
acl acme_path path_beg /.well-known/acme-challenge/
# Redirect all HTTP traffic to HTTPS except ACME challenge requests
redirect scheme https if !acme_path
# Use the appropriate backend based on hostname if it's an ACME challenge request
use_backend acme_backend if acme_path
#--------------------------------------------------------------------- #---------------------------------------------------------------------
# Frontend configuration for handling multiple domains with SNI # Backend to handle ACME challenge requests
#--------------------------------------------------------------------- #---------------------------------------------------------------------
frontend web backend acme_backend
bind :80 server local_acme 127.0.0.1:8080
bind :443 ssl crt /etc/haproxy/certs/ strict-sni
# Handling for ACME challenge paths
acl acme_challenge path_beg /.well-known/acme-challenge/
use_backend acme_challenge_backend if acme_challenge
#--------------------------------------------------------------------- #---------------------------------------------------------------------
# Backend configuration for ACME challenge # Frontend for HTTPS traffic (port 443) with SNI and strict-sni
#--------------------------------------------------------------------- #---------------------------------------------------------------------
backend acme_challenge_backend frontend https_frontend
server acme_challenge 127.0.0.1:8080 bind *:443 ssl crt /etc/haproxy/certs strict-sni
http-request capture req.hdr(host) len 64
# Define ACLs for routing based on hostname
acl host_git hdr(host) -i git.maks-it.com
acl host_cr hdr(host) -i cr.maks-it.com
# Use appropriate backend based on SNI hostname
use_backend git_backend if host_git
use_backend cr_backend if host_cr
#---------------------------------------------------------------------
# Backend for git.maks-it.com
#---------------------------------------------------------------------
backend git_backend
http-request set-header X-Forwarded-Proto https
http-request set-header X-Forwarded-Host %[hdr(host)]
server git_server gitsrv0002.corp.maks-it.com:3000
#---------------------------------------------------------------------
# Backend for cr.maks-it.com
#---------------------------------------------------------------------
backend cr_backend
http-request set-header X-Forwarded-Proto https
http-request set-header X-Forwarded-Host %[hdr(host)]
server cr_server hcrsrv0001.corp.maks-it.com:80
#---------------------------------------------------------------------
# letsencrypt load balancer
#---------------------------------------------------------------------
frontend letsencrypt
bind *:8080
mode http
acl path_well_known_acme path_beg /.well-known/acme-challenge/
acl path_swagger path_beg /swagger/
acl path_api path_beg /api/
use_backend letsencrypt_server if path_well_known_acme
use_backend letsencrypt_server if path_swagger
use_backend letsencrypt_server if path_api
default_backend letsencrypt_app
backend letsencrypt_server
mode http
server server1 127.0.0.1:9000 check
backend letsencrypt_app
mode http
server app1 127.0.0.1:3000 check
``` ```
## MaksIT agent installation
From your home directory
## MaksIT agent
```bash ```bash
openssl rand -base64 32 git clone https://github.com/MAKS-IT-COM/certs-ui.git
``` ```
```bash ```bash
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm cd certs-ui/src/Agent
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 ```bash
[Unit] sudo sh ./build_and_deploy.sh
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] ## Maks IT LetsEncrypt server installation
WantedBy=multi-user.target
From your home directory
```bash
git clone https://github.com/MAKS-IT-COM/certs-ui.git
``` ```
```bash ```bash
sudo systemctl daemon-reload cd certs-ui/src
sudo systemctl enable --now maks-it-agent.service ```
sudo systemctl status maks-it-agent.service
```bash
podman-compose -f docker-compose.final.yml up
``` ```

34
pipeline.json Normal file
View File

@ -0,0 +1,34 @@
{
"version": "1.0",
"name": "CI/CD Pipeline",
"jobs": {
"build-and-push": {
"steps": [
{
"agent": "kaniko",
"context": "src",
"dockerfile-path": "LetsEncryptServer/Dockerfile",
"image-name": "${{ env.REGISTRY_URL }}/${{ env.USERNAME }}/certs-ui-server:latest",
"username": "${{ env.USERNAME }}",
"password": "${{ env.PASSWORD }}"
},
{
"agent": "kaniko",
"context": "src",
"dockerfile-path": "ClientApp/Dockerfile",
"image-name": "${{ env.REGISTRY_URL }}/${{ env.USERNAME }}/certs-ui-clientapp:latest",
"username": "${{ env.USERNAME }}",
"password": "${{ env.PASSWORD }}"
}
]
},
"deploy": {
"steps": []
}
}
}

View File

@ -1,12 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
@ -19,5 +21,4 @@
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.002.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Agent - Backup (1)", "Agent - Backup (1).csproj", "{392E9E34-E17C-4118-9C83-52AF52A56E54}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Agent - Backup", "Agent - Backup.csproj", "{18049E33-180E-41F1-8343-5BCD4755B2A8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Agent", "Agent.csproj", "{2C1A9C83-0B26-450C-A874-0B8DBD251B0F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{392E9E34-E17C-4118-9C83-52AF52A56E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{392E9E34-E17C-4118-9C83-52AF52A56E54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{392E9E34-E17C-4118-9C83-52AF52A56E54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{392E9E34-E17C-4118-9C83-52AF52A56E54}.Release|Any CPU.Build.0 = Release|Any CPU
{18049E33-180E-41F1-8343-5BCD4755B2A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{18049E33-180E-41F1-8343-5BCD4755B2A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{18049E33-180E-41F1-8343-5BCD4755B2A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{18049E33-180E-41F1-8343-5BCD4755B2A8}.Release|Any CPU.Build.0 = Release|Any CPU
{2C1A9C83-0B26-450C-A874-0B8DBD251B0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C1A9C83-0B26-450C-A874-0B8DBD251B0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C1A9C83-0B26-450C-A874-0B8DBD251B0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C1A9C83-0B26-450C-A874-0B8DBD251B0F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {281E7450-1EDC-4E77-B04F-C14F65273D90}
EndGlobalSection
EndGlobal

View File

@ -1,6 +1,29 @@
namespace MaksIT.Agent { namespace MaksIT.Agent {
public class Configuration { public class Configuration {
public required string ApiKey { get; set; }
public required string CertsPath { get; set; } private string? _apiKey;
public string ApiKey {
get {
var env = Environment.GetEnvironmentVariable("MAKS-IT_AGENT_API_KEY");
return env ?? _apiKey ?? string.Empty;
}
set {
_apiKey = value;
}
}
private string? _certsPath;
public string CertsPath {
get {
var env = Environment.GetEnvironmentVariable("MAKS-IT_AGENT_CERTS_PATH");
return env ?? _certsPath ?? string.Empty;
}
set {
_certsPath = value;
}
}
} }
} }

View File

@ -12,15 +12,20 @@ namespace MaksIT.Agent.Controllers;
public class CertsController : ControllerBase { public class CertsController : ControllerBase {
private readonly Configuration _appSettings; private readonly Configuration _appSettings;
private readonly ILogger<CertsController> _logger;
public CertsController( public CertsController(
IOptions<Configuration> appSettings IOptions<Configuration> appSettings,
ILogger<CertsController> logger
) { ) {
_logger = logger;
_appSettings = appSettings.Value; _appSettings = appSettings.Value;
} }
[HttpPost("[action]")] [HttpPost("[action]")]
public IActionResult Upload([FromBody] CertsUploadRequest requestData) { public IActionResult Upload([FromBody] CertsUploadRequest requestData) {
_logger.LogInformation("Uploading certificates");
foreach (var (fileName, fileContent) in requestData.Certs) { foreach (var (fileName, fileContent) in requestData.Certs) {
System.IO.File.WriteAllText(Path.Combine(_appSettings.CertsPath, fileName), fileContent); System.IO.File.WriteAllText(Path.Combine(_appSettings.CertsPath, fileName), fileContent);
} }

View File

@ -1,23 +1,14 @@
{ {
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:7748",
"sslPort": 0
}
},
"profiles": { "profiles": {
"http": { "http": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "swagger", "launchUrl": "swagger",
"applicationUrl": "http://localhost:5000",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5000"
}, },
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
@ -26,6 +17,24 @@
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTP_PORTS": "5000"
},
"publishAllPorts": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:7748",
"sslPort": 0
} }
} }
} }

View File

@ -11,7 +11,7 @@ APPSETTINGS_FILE="appsettings.json"
NO_NEW_KEY_FLAG="--no-new-key" NO_NEW_KEY_FLAG="--no-new-key"
# Update package index and install the Microsoft package repository # Update package index and install the Microsoft package repository
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm # sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm
sudo dnf install -y dotnet-sdk-8.0 sudo dnf install -y dotnet-sdk-8.0
# Check if the service exists and stop it if it does # Check if the service exists and stop it if it does
@ -33,12 +33,9 @@ if [[ "$1" != "$NO_NEW_KEY_FLAG" ]]; then
jq --arg newApiKey "$NEW_API_KEY" '.Configuration.ApiKey = $newApiKey' $APPSETTINGS_FILE > tmp.$$.json && mv tmp.$$.json $APPSETTINGS_FILE jq --arg newApiKey "$NEW_API_KEY" '.Configuration.ApiKey = $newApiKey' $APPSETTINGS_FILE > tmp.$$.json && mv tmp.$$.json $APPSETTINGS_FILE
fi fi
cd
# Build and publish the .NET application # Build and publish the .NET application
cd "$(dirname "$(realpath "$0")")/Agent" sudo dotnet build Agent.csproj --configuration Release
sudo dotnet build --configuration Release sudo dotnet publish Agent.csproj -c Release -o $INSTALL_DIR
sudo dotnet publish -c Release -o $INSTALL_DIR
# Create the systemd service unit file # Create the systemd service unit file
sudo bash -c "cat > $SERVICE_FILE <<EOL sudo bash -c "cat > $SERVICE_FILE <<EOL

View File

@ -25,7 +25,9 @@ const GetApiRoute = (route: ApiRoutes, ...args: string[]): string => {
args.forEach((arg) => { args.forEach((arg) => {
result = result.replace(/{.*?}/, arg) result = result.replace(/{.*?}/, arg)
}) })
// TODO: need env var
return `http://localhost:8080/${result}` return `http://localhost:8080/${result}`
//return `http://websrv0001.corp.maks-it.com:8080/${result}`
} }
export { GetApiRoute, ApiRoutes } export { GetApiRoute, ApiRoutes }

View File

@ -1,11 +1,19 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using MaksIT.LetsEncrypt.Services; using MaksIT.LetsEncrypt.Services;
using Microsoft.Extensions.Configuration;
namespace MaksIT.LetsEncrypt.Extensions; namespace MaksIT.LetsEncrypt.Extensions;
public static class ServiceCollectionExtensions { public static class ServiceCollectionExtensions {
public static void RegisterLetsEncrypt(this IServiceCollection services) { public static void RegisterLetsEncrypt(this IServiceCollection services, ILetsEncryptConfiguration appSettings) {
var config = new LetsEncryptConfiguration {
Staging = appSettings.Staging,
Production = appSettings.Production
};
services.AddSingleton(config);
services.AddHttpClient<ILetsEncryptService, LetsEncryptService>(); services.AddHttpClient<ILetsEncryptService, LetsEncryptService>();
} }
} }

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MaksIT.LetsEncrypt {
public interface ILetsEncryptConfiguration {
string Production { get; set; }
string Staging { get; set; }
}
public class LetsEncryptConfiguration : ILetsEncryptConfiguration {
public required string Production { get; set; }
public required string Staging { get; set; }
}
}

View File

@ -22,6 +22,7 @@ using MaksIT.LetsEncrypt.Models.Interfaces;
using MaksIT.LetsEncrypt.Models.Requests; using MaksIT.LetsEncrypt.Models.Requests;
using MaksIT.LetsEncrypt.Entities.Jws; using MaksIT.LetsEncrypt.Entities.Jws;
using MaksIT.LetsEncrypt.Entities.LetsEncrypt; using MaksIT.LetsEncrypt.Entities.LetsEncrypt;
using Microsoft.Extensions.Options;
namespace MaksIT.LetsEncrypt.Services; namespace MaksIT.LetsEncrypt.Services;
@ -39,14 +40,18 @@ public interface ILetsEncryptService {
public class LetsEncryptService : ILetsEncryptService { public class LetsEncryptService : ILetsEncryptService {
private readonly ILogger<LetsEncryptService> _logger; private readonly ILogger<LetsEncryptService> _logger;
private readonly LetsEncryptConfiguration _appSettings;
private readonly HttpClient _httpClient; private readonly HttpClient _httpClient;
private readonly IMemoryCache _memoryCache; private readonly IMemoryCache _memoryCache;
public LetsEncryptService( public LetsEncryptService(
ILogger<LetsEncryptService> logger, ILogger<LetsEncryptService> logger,
LetsEncryptConfiguration appSettings,
HttpClient httpClient, HttpClient httpClient,
IMemoryCache cache) { IMemoryCache cache
) {
_logger = logger; _logger = logger;
_appSettings = appSettings;
_httpClient = httpClient; _httpClient = httpClient;
_memoryCache = cache; _memoryCache = cache;
} }
@ -66,9 +71,7 @@ public class LetsEncryptService : ILetsEncryptService {
state.IsStaging = isStaging; state.IsStaging = isStaging;
// TODO: need to propagate from Configuration // TODO: need to propagate from Configuration
_httpClient.BaseAddress ??= new Uri(isStaging _httpClient.BaseAddress ??= new Uri(isStaging ? _appSettings.Staging : _appSettings.Production);
? "https://acme-staging-v02.api.letsencrypt.org/directory"
: "https://acme-v02.api.letsencrypt.org/directory");
if (state.Directory == null) { if (state.Directory == null) {
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("directory", UriKind.Relative)); var request = new HttpRequestMessage(HttpMethod.Get, new Uri("directory", UriKind.Relative));

View File

@ -1,16 +1,85 @@
namespace MaksIT.LetsEncryptServer { using MaksIT.LetsEncrypt;
namespace MaksIT.LetsEncryptServer {
public class Agent { public class Agent {
public required string AgentHostname { get; set; }
public required int AgentPort { get; set; }
public required string AgentKey { get; set; }
public required string ServiceToReload { get; set; } private string? _agentHostname;
public string AgentHostname {
get {
var env = Environment.GetEnvironmentVariable("MAKS-IT_AGENT_HOSTNAME");
return env ?? _agentHostname ?? string.Empty;
}
set {
_agentHostname = value;
}
}
private int? _agentPort;
public int AgentPort {
get {
var env = Environment.GetEnvironmentVariable("MAKS-IT_AGENT_PORT");
return env != null ? int.Parse(env) : _agentPort ?? 0;
}
set {
_agentPort = value;
}
}
private string? _agentKey;
public string AgentKey {
get {
var env = Environment.GetEnvironmentVariable("MAKS-IT_AGENT_KEY");
return env ?? _agentKey ?? string.Empty;
}
set {
_agentKey = value;
}
}
private string? _serviceToReload;
public string ServiceToReload {
get {
var env = Environment.GetEnvironmentVariable("MAKS-IT_AGENT_SERVICE");
return env ?? _serviceToReload ?? string.Empty;
}
set {
_serviceToReload = value;
}
}
} }
public class Configuration {
public required string Production { get; set; }
public required string Staging { get; set; }
public class Configuration : ILetsEncryptConfiguration {
private string? _production;
public string Production {
get {
var env = Environment.GetEnvironmentVariable("LETSENCRYPT_SERVER_PRODUCTION");
return env ?? _production ?? string.Empty;
}
set {
_production = value;
}
}
private string? _staging;
public string Staging {
get {
var env = Environment.GetEnvironmentVariable("LETSENCRYPT_SERVER_STAGING");
return env ?? _staging ?? string.Empty;
}
set {
_staging = value;
}
}
public required Agent Agent { get; set; } public required Agent Agent { get; set; }
} }
} }

View File

@ -3,7 +3,7 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app USER app
WORKDIR /app WORKDIR /app
EXPOSE 8080 EXPOSE 5000
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release ARG BUILD_CONFIGURATION=Release

View File

@ -3,6 +3,7 @@ using MaksIT.LetsEncrypt.Services;
using MaksIT.LetsEncryptServer.Services; using MaksIT.LetsEncryptServer.Services;
using MaksIT.LetsEncryptServer.BackgroundServices; using MaksIT.LetsEncryptServer.BackgroundServices;
using MaksIT.LetsEncryptServer.Middlewares; using MaksIT.LetsEncryptServer.Middlewares;
using MaksIT.LetsEncrypt.Extensions;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -28,7 +29,8 @@ builder.Services.AddCors();
builder.Services.AddMemoryCache(); builder.Services.AddMemoryCache();
builder.Services.AddHttpClient<ILetsEncryptService, LetsEncryptService>(); builder.Services.RegisterLetsEncrypt(appSettings);
builder.Services.AddSingleton<ICacheService, CacheService>(); builder.Services.AddSingleton<ICacheService, CacheService>();
builder.Services.AddSingleton<ICertsFlowService, CertsFlowService>(); builder.Services.AddSingleton<ICertsFlowService, CertsFlowService>();
builder.Services.AddSingleton<IAccountService, AccountService>(); builder.Services.AddSingleton<IAccountService, AccountService>();

View File

@ -12,8 +12,8 @@
"Staging": "https://acme-staging-v02.api.letsencrypt.org/directory", "Staging": "https://acme-staging-v02.api.letsencrypt.org/directory",
"Agent": { "Agent": {
"AgentHostname": "http://lblsrv0001.corp.maks-it.com", "AgentHostname": "http://websrv0001.corp.maks-it.com",
"AgentPort": 5000, "AgentPort": 9000,
"AgentKey": "UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=", "AgentKey": "UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=",
"ServiceToReload": "haproxy" "ServiceToReload": "haproxy"

View File

@ -5,39 +5,39 @@
"Match": { "Match": {
"Path": "/.well-known/acme-challenge/{**catch-all}" "Path": "/.well-known/acme-challenge/{**catch-all}"
}, },
"ClusterId": "letsencryptserver" "ClusterId": "letsencrypt-server"
}, },
"swagger-route": { "swagger-route": {
"Match": { "Match": {
"Path": "/swagger/{**catch-all}" "Path": "/swagger/{**catch-all}"
}, },
"ClusterId": "letsencryptserver" "ClusterId": "letsencrypt-server"
}, },
"api-route": { "api-route": {
"Match": { "Match": {
"Path": "/api/{**catch-all}" "Path": "/api/{**catch-all}"
}, },
"ClusterId": "letsencryptserver" "ClusterId": "letsencrypt-server"
}, },
"default-route": { "default-route": {
"Match": { "Match": {
"Path": "{**catch-all}" "Path": "{**catch-all}"
}, },
"ClusterId": "letsencryptapp" "ClusterId": "letsencrypt-app"
} }
}, },
"Clusters": { "Clusters": {
"letsencryptserver": { "letsencrypt-server": {
"Destinations": { "Destinations": {
"destination1": { "destination1": {
"Address": "http://letsencryptserver:5000/" "Address": "http://letsencrypt-server:5000/"
} }
} }
}, },
"letsencryptapp": { "letsencrypt-app": {
"Destinations": { "Destinations": {
"destination1": { "destination1": {
"Address": "http://letsencryptapp:3000/" "Address": "http://letsencrypt-app:3000/"
} }
} }
} }

View File

@ -0,0 +1,46 @@
services:
letsencrypt-app:
image: ${DOCKER_REGISTRY-}letsencrypt-app
build:
context: .
dockerfile: ClientApp/Dockerfile
container_name: letsencrypt-app
environment:
- ASPNETCORE_ENVIRONMENT=Production
- LETSENCRYPT_SERVER=http://websrv0001.corp.maks-it.com
ports:
- "3000:3000"
network_mode: "host"
letsencrypt-server:
image: ${DOCKER_REGISTRY-}letsencrypt-server
build:
context: .
dockerfile: LetsEncryptServer/Dockerfile
container_name: letsencrypt-server
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_HTTP_PORTS=9000
- LETSENCRYPT_SERVER_PRODUCTION=https://acme-v02.api.letsencrypt.org/directory
- LETSENCRYPT_SERVER_STAGING=https://acme-staging-v02.api.letsencrypt.org/directory
- MAKS_IT_AGENT_HOSTNAME=http://websrv0001.corp.maks-it.com
- MAKS-IT_AGENT_PORT=5000
- MAKS-IT_AGENT_KEY=UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=
- MAKS-IT_AGENT_SERVICE=haproxy
volumes:
- ./docker-compose/LetsEncryptServer/acme:/app/acme
- ./docker-compose/LetsEncryptServer/cache:/app/cache
ports:
- "9000:9000"
network_mode: "host"
curl-test:
image: curlimages/curl:latest
container_name: curl-test
command: >
curl --location http://websrv0001.corp.maks-it.com:5000/HelloWorld
--header "x-api-key: UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I="
restart: "no"
network_mode: "host"

View File

@ -1,24 +1,43 @@
version: '3.9'
services: services:
reverseProxy: reverse-proxy:
container_name: reverse-proxy
ports: ports:
- "8080:8080" - "8080:8080"
depends_on: depends_on:
- letsencryptapp - letsencrypt-app
- letsencryptserver - letsencrypt-server
networks:
- maks-it
# letsencryptapp: letsencrypt-app:
container_name: letsencrypt-app
environment:
- ASPNETCORE_ENVIRONMENT=Development
- LETSENCRYPT_SERVER=http://localhost:8080
# ports: # ports:
# - "3000:3000" # - "3000:3000"
networks:
- maks-it
letsencryptserver: letsencrypt-server:
container_name: letsencrypt-server
environment: environment:
- ASPNETCORE_ENVIRONMENT=Development - ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=5000 - ASPNETCORE_HTTP_PORTS=5000
- LETSENCRYPT_SERVER_PRODUCTION=https://acme-v02.api.letsencrypt.org/directory
- LETSENCRYPT_SERVER_STAGING=https://acme-staging-v02.api.letsencrypt.org/directory
- MAKS_IT_AGENT_HOSTNAME=http://websrv0001.corp.maks-it.com
- MAKS-IT_AGENT_PORT=5000
- MAKS-IT_AGENT_KEY=UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=
- MAKS-IT_AGENT_SERVICE=haproxy
volumes: volumes:
- ./docker-compose/LetsEncryptServer/acme:/app/bin/Debug/net8.0/acme - ./docker-compose/LetsEncryptServer/acme:/app/bin/Debug/net8.0/acme
- ./docker-compose/LetsEncryptServer/cache:/app/bin/Debug/net8.0/cache - ./docker-compose/LetsEncryptServer/cache:/app/bin/Debug/net8.0/cache
ports: ports:
- "5000:5000" - "5000:5000"
networks:
- maks-it
networks:
maks-it:
driver: bridge

View File

@ -1,20 +1,18 @@
version: '3.9'
services: services:
letsencryptapp: letsencrypt-app:
image: ${DOCKER_REGISTRY-}letsencryptapp image: ${DOCKER_REGISTRY-}letsencrypt-app
build: build:
context: . context: .
dockerfile: ClientApp/Dockerfile dockerfile: ClientApp/Dockerfile
reverseProxy: reverse-proxy:
image: ${DOCKER_REGISTRY-}reverseproxy image: ${DOCKER_REGISTRY-}reverse-proxy
build: build:
context: . context: .
dockerfile: ReverseProxy/Dockerfile dockerfile: ReverseProxy/Dockerfile
letsencryptserver: letsencrypt-server:
image: ${DOCKER_REGISTRY-}letsencryptserver image: ${DOCKER_REGISTRY-}letsencrypt-server
build: build:
context: . context: .
dockerfile: LetsEncryptServer/Dockerfile dockerfile: LetsEncryptServer/Dockerfile