mirror of
https://github.com/MAKS-IT-COM/maksit-certs-ui.git
synced 2025-12-31 04:00:03 +01:00
(feature): release 3.3.1
This commit is contained in:
parent
18c5f72cf2
commit
40c23c61ef
337
README.md
337
README.md
@ -1,7 +1,10 @@
|
||||
# MaksIT.CertsUI - Container-based Let's Encrypt ACME client with WebUI
|
||||
# MaksIT.CertsUI – Modern container-native ACME client with a full WebUI experience
|
||||
|
||||
Powerful client to obtain and manage Let's Encrypt HTTPS certificates.
|
||||
This client currently supports the HTTP-01 challenge and is designed to follow the official [Let's Encrypt requirements and guidelines](https://letsencrypt.org/docs/), implementing the ACME protocol and adhering to recommended security and operational practices.
|
||||
MaksIT.CertsUI is a powerful, container-native ACMEv2 client built to simplify and automate the entire lifecycle of HTTPS certificates issued by Let’s Encrypt. It is an independent, unofficial project and is not affiliated with or endorsed by Let’s Encrypt or ISRG.
|
||||
|
||||
Designed for modern infrastructure, it combines a robust WebAPI, intuitive WebUI, and lightweight edge Agent to deliver fully automated certificate issuance, renewal, and deployment across Docker, Podman, and Kubernetes environments. MaksIT.CertsUI supports the HTTP-01 challenge and follows the official [Let’s Encrypt guidelines](https://letsencrypt.org/docs/) while implementing recommended security and operational best practices.
|
||||
|
||||
---
|
||||
|
||||
|
||||
If you find this project useful, please consider supporting its development:
|
||||
@ -13,10 +16,8 @@ If you find this project useful, please consider supporting its development:
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [MaksIT.CertsUI - Container-based Let's Encrypt ACME client with WebUI](#maksitcertsui---container-based-lets-encrypt-acme-client-with-webui)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Versions History](#versions-history)
|
||||
- [Architecture](#architecture)
|
||||
- [Versions History](#versions-history)
|
||||
- [Architecture](#architecture)
|
||||
- [Current Limitations](#current-limitations)
|
||||
- [Architecture Scheme](#architecture-scheme)
|
||||
- [Architecture Description](#architecture-description)
|
||||
@ -24,23 +25,21 @@ If you find this project useful, please consider supporting its development:
|
||||
- [MaksIT.CertsUI WebUI](#maksitcertsui-webui)
|
||||
- [MaksIT.CertsUI WebAPI](#maksitcertsui-webapi)
|
||||
- [Flow Overview](#flow-overview)
|
||||
- [HAProxy configuration](#haproxy-configuration)
|
||||
- [Explanation](#explanation)
|
||||
- [MaksIT.CertsUI Agent installation](#maksitcertsui-agent-installation)
|
||||
- [MaksIT.CertsUI Server Installation on Linux with Podman Compose](#maksitcertsui-server-installation-on-linux-with-podman-compose)
|
||||
- [MaksIT.CertsUI Agent installation](https://github.com/MAKS-IT-COM/maksit-certs-ui-agent)
|
||||
- [MaksIT.CertsUI Server Installation on Linux with Podman Compose](#maksitcertsui-server-installation-on-linux-with-podman-compose)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Running the Project with Podman Compose](#running-the-project-with-podman-compose)
|
||||
- [MaksIT.CertsUI Server Installation on Windows with Docker Compose](#maksitcertsui-server-installation-on-windows-with-docker-compose)
|
||||
- [MaksIT.CertsUI Server Installation on Windows with Docker Compose](#maksitcertsui-server-installation-on-windows-with-docker-compose)
|
||||
- [Prerequisites](#prerequisites-1)
|
||||
- [Secrets and Configuration](#secrets-and-configuration)
|
||||
- [Running the Project with Docker Compose](#running-the-project-with-docker-compose)
|
||||
- [MaksIT.CertsUI Server installation on Kubernetes](#maksitcertsui-server-installation-on-kubernetes)
|
||||
- [MaksIT.CertsUI Server installation on Kubernetes](#maksitcertsui-server-installation-on-kubernetes)
|
||||
- [1. Add MaksIT Helm Repository](#1-add-maksit-helm-repository)
|
||||
- [2. Prepare Namespace, Secrets, and ConfigMap](#2-prepare-namespace-secrets-and-configmap)
|
||||
- [3. Create a Minimal Custom Values File](#3-create-a-minimal-custom-values-file)
|
||||
- [4. Install the Helm Chart](#4-install-the-helm-chart)
|
||||
- [MaksIT.CertsUI Interface Overview](#maksitcertsui-interface-overview)
|
||||
- [Contact](#contact)
|
||||
- [MaksIT.CertsUI Interface Overview](#maksitcertsui-interface-overview)
|
||||
- [Contact](#contact)
|
||||
|
||||
|
||||
## Versions History
|
||||
@ -51,6 +50,7 @@ If you find this project useful, please consider supporting its development:
|
||||
* 11 Aug, 2024 - V3.1.0 (Release)
|
||||
* 11 Sep, 2025 - V3.2.0 New WebUI with authentication
|
||||
* 15 Nov, 2025 - V3.3.0 Pre release
|
||||
* 22 Nov, 2025 - V3.3.1 Public release
|
||||
|
||||
|
||||
---
|
||||
@ -108,21 +108,7 @@ These limitations are intentional to keep the architecture simple and reliable f
|
||||
|
||||
The **MaksIT.CertsUI Agent** is a lightweight service responsible for **receiving cached certificates** from the **MaksIT.CertsUI** server and **deploying them to the local file system** used by your reverse proxy (e.g., **HAProxy** or **Nginx**). It also handles **proxy service reloads** to activate new certificates.
|
||||
|
||||
|
||||
**Language Independence:**
|
||||
A standard **C# WebAPI implementation** of the Agent is available in this repository for immediate use or customization. However, the Agent is fully independent from the MaksIT.CertsUI server and communicates via standard **HTTP APIs**. This means you can implement the Agent in **any programming language or framework** that supports HTTP endpoints (such as **C#**, **Go**, **Python**, **Rust**, **Node.js**, etc.). The only requirements are:
|
||||
|
||||
- Ability to **receive certificate files via HTTP**
|
||||
- Ability to **write files** to the proxy’s certificate directory
|
||||
- Ability to **reload or restart** the proxy process
|
||||
|
||||
|
||||
**Security:**
|
||||
Communication between the Agent and the **MaksIT.CertsUI** server is secured using a **shared API key**. This ensures that only authorized servers can deploy certificates and trigger proxy reloads, protecting your edge infrastructure from unauthorized access.
|
||||
|
||||
> **Warning:** Never commit secrets or API keys to version control. Always use strong, unique secrets and passwords.
|
||||
|
||||
This flexibility allows you to integrate the Agent into diverse environments and choose the best technology stack for your edge server.
|
||||
Check **Agent** repository for more details and installation instructions: [MaksIT.CertsUI Agent](https://github.com/MAKS-IT-COM/maksit-certs-ui-agent.git)
|
||||
|
||||
#### MaksIT.CertsUI WebUI
|
||||
|
||||
@ -204,158 +190,6 @@ The Webapi is designed for deployment in secure environments such as Kubernetes
|
||||
> **Note:** Currently, only HTTP-01 challenges and a single Kubernetes replica are supported by this solution.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## HAProxy configuration
|
||||
|
||||
```bash
|
||||
sudo mkdir /etc/haproxy/certs
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo nano /etc/haproxy/haproxy.cfg
|
||||
```
|
||||
|
||||
```cfg
|
||||
#---------------------------------------------------------------------
|
||||
# Global settings
|
||||
#---------------------------------------------------------------------
|
||||
global
|
||||
log 127.0.0.1 local2
|
||||
chroot /var/lib/haproxy
|
||||
pidfile /var/run/haproxy.pid
|
||||
maxconn 4000
|
||||
user haproxy
|
||||
group haproxy
|
||||
daemon
|
||||
stats socket /var/lib/haproxy/stats
|
||||
ssl-default-bind-ciphers PROFILE=SYSTEM
|
||||
ssl-default-server-ciphers PROFILE=SYSTEM
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# common defaults that all the 'listen' and 'backend' sections will
|
||||
# use if not designated in their block
|
||||
#---------------------------------------------------------------------
|
||||
defaults
|
||||
mode http
|
||||
log global
|
||||
option httplog
|
||||
option dontlognull
|
||||
option http-server-close
|
||||
option forwardfor except 127.0.0.0/8
|
||||
option redispatch
|
||||
retries 3
|
||||
timeout http-request 10s
|
||||
timeout queue 1m
|
||||
timeout connect 10s
|
||||
timeout client 1m
|
||||
timeout server 1m
|
||||
timeout http-keep-alive 10s
|
||||
timeout check 10s
|
||||
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
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Backend to handle ACME challenge requests
|
||||
#---------------------------------------------------------------------
|
||||
backend acme_backend
|
||||
#server local_acme 172.16.0.5:8080
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Frontend for HTTPS traffic (port 443) with SNI and strict-sni
|
||||
#---------------------------------------------------------------------
|
||||
frontend https_frontend
|
||||
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_homepage hdr(host) -i maks-it.com
|
||||
|
||||
# Use appropriate backend based on SNI hostname
|
||||
use_backend homepage_backend if host_homepage
|
||||
|
||||
default_backend homepage_backend
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Backend for maks-it.com
|
||||
#---------------------------------------------------------------------
|
||||
backend homepage_backend
|
||||
http-request set-header X-Forwarded-Proto https
|
||||
http-request set-header X-Forwarded-Host %[hdr(host)]
|
||||
server homepage_server 172.16.0.10:8080
|
||||
```
|
||||
|
||||
### Explanation
|
||||
* ACME Challenge Handling:
|
||||
The http_frontend listens on port 80 and checks if the request path starts with /.well-known/acme-challenge/. These requests are required by Let's Encrypt for domain validation and are forwarded to the acme_backend. All other HTTP requests are redirected to HTTPS.
|
||||
* HTTPS Frontend:
|
||||
The https_frontend listens on port 443, uses SNI (Server Name Indication) to serve the correct certificate, and routes requests to the appropriate backend based on the hostname.
|
||||
* Backends:
|
||||
* acme_backend should point to your ACME challenge responder (such as your LetsEncrypt client).
|
||||
* homepage_backend is an example backend for your main site, forwarding requests to your application server.
|
||||
* Certificate Storage:
|
||||
Place your SSL certificates in /etc/haproxy/certs. Each certificate file should contain the full certificate chain and private key.
|
||||
|
||||
## MaksIT.CertsUI Agent installation
|
||||
|
||||
Agent should be installed on same machine with your reverse proxy.
|
||||
|
||||
From your home directory
|
||||
|
||||
```bash
|
||||
git clone https://github.com/MAKS-IT-COM/certs-ui.git
|
||||
```
|
||||
|
||||
```bash
|
||||
cd certs-ui/src/Agent
|
||||
```
|
||||
|
||||
Edit `appsettings.json` configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"Configuration": {
|
||||
"ApiKey": "<your-agent-key>",
|
||||
"CertsPath": "<your-certs-dir-path>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**Note:**
|
||||
Replace `<your-auth-secret>` with your shared API key and `<your-certs-dir-path>` with the path to your certificates directory (e.g., `/etc/haproxy/certs` as referenced in `haproxy.cfg`).
|
||||
> **Warning:** Never commit secrets or API keys to version control. Always use strong, unique secrets and passwords.
|
||||
|
||||
If you are using a **RHEL-based** distribution, you can deploy the agent with:
|
||||
|
||||
```bash
|
||||
sudo sh ./build_and_deploy.sh
|
||||
```
|
||||
|
||||
This script will create the `maks-it-agent` service and open port `5000` for communication.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## MaksIT.CertsUI Server Installation on Linux with Podman Compose
|
||||
@ -365,6 +199,11 @@ Podman Compose usage to orchestrate multiple **MaksIT.CertsUI** services on Linu
|
||||
### Prerequisites
|
||||
|
||||
- [Podman](https://podman.io/getting-started/installation)
|
||||
|
||||
- sudo dnf install podman-compose -y
|
||||
|
||||
|
||||
|
||||
- Create these folders:
|
||||
- `/opt/Compose/MaksIT.CertsUI/acme`
|
||||
- `/opt/Compose/MaksIT.CertsUI/cache`
|
||||
@ -377,7 +216,7 @@ Podman Compose usage to orchestrate multiple **MaksIT.CertsUI** services on Linu
|
||||
Bash command to use:
|
||||
|
||||
```bash
|
||||
mkdir -p /opt/Compose/MaksIT.CertsUI/acme \
|
||||
sudo mkdir -p /opt/Compose/MaksIT.CertsUI/acme \
|
||||
/opt/Compose/MaksIT.CertsUI/cache \
|
||||
/opt/Compose/MaksIT.CertsUI/data \
|
||||
/opt/Compose/MaksIT.CertsUI/tmp \
|
||||
@ -391,7 +230,7 @@ Create the following files in the appropriate folders:
|
||||
**1. Create the file `/opt/Compose/MaksIT.CertsUI/secrets/appsecrets.json` with this command:**
|
||||
|
||||
```bash
|
||||
cat > /opt/Compose/MaksIT.CertsUI/secrets/appsecrets.json <<EOF
|
||||
sudo tee /opt/Compose/MaksIT.CertsUI/secrets/appsecrets.json > /dev/null <<EOF
|
||||
{
|
||||
"Configuration": {
|
||||
"Auth": {
|
||||
@ -413,7 +252,7 @@ Make sure `<your-agent-key>` matches the key configured in your agent deployment
|
||||
**2. Create the file `/opt/Compose/MaksIT.CertsUI/configMap/appsettings.json` with this command:**
|
||||
|
||||
```bash
|
||||
cat > /opt/Compose/MaksIT.CertsUI/configMap/appsettings.json <<EOF
|
||||
sudo tee /opt/Compose/MaksIT.CertsUI/configMap/appsettings.json <<EOF
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
@ -450,7 +289,7 @@ Replace all JWT-related placeholder values `<your-issuer>`, `<your-audience>` an
|
||||
**3. Create the file `/opt/Compose/MaksIT.CertsUI/client/config.js` with this command:**
|
||||
|
||||
```bash
|
||||
cat > /opt/Compose/MaksIT.CertsUI/configMap/appsettings.json <<EOF
|
||||
sudo tee /opt/Compose/MaksIT.CertsUI/client/config.js <<EOF
|
||||
window.RUNTIME_CONFIG = {
|
||||
API_URL: "http://<your-server-hostname>/api"
|
||||
};
|
||||
@ -464,7 +303,8 @@ EOF
|
||||
|
||||
In the project root (`/opt/Compose/MaksIT.CertsUI`), create a new file named `docker-compose.yml` with the following content:
|
||||
|
||||
```yaml
|
||||
```bash
|
||||
sudo tee /opt/Compose/MaksIT.CertsUI/docker-compose.yml <<EOF
|
||||
services:
|
||||
reverse-proxy:
|
||||
image: cr.maks-it.com/certs-ui/reverseproxy:latest
|
||||
@ -504,11 +344,72 @@ services:
|
||||
networks:
|
||||
certs-ui-network:
|
||||
driver: bridge
|
||||
EOF
|
||||
```
|
||||
|
||||
**Note:**
|
||||
- Adjust volume paths if changed
|
||||
|
||||
**1. Run Podman compose in Rootfull mode (The only supported by podman-compose):**
|
||||
|
||||
```bash
|
||||
sudo chown -R 1654:1654 /opt/Compose/MaksIT.CertsUI/{data,cache,acme}
|
||||
sudo chmod -R 775 /opt/Compose/MaksIT.CertsUI/{data,cache,acme}
|
||||
|
||||
sudo chown -R 1654:1654 /opt/Compose/MaksIT.CertsUI/tmp
|
||||
sudo chmod 1777 /opt/Compose/MaksIT.CertsUI/tmp
|
||||
|
||||
sudo su -
|
||||
sudo bash -c 'echo "export PATH=/usr/local/bin:/usr/local/sbin:\$PATH" >> /root/.bashrc'
|
||||
|
||||
exit
|
||||
sudo su -
|
||||
|
||||
podman compose -f docker-compose.yml up --build
|
||||
```
|
||||
|
||||
**2. Run Podman compose in Rootless mode (Not supported by podman-compose on Alma10, havent tested):**
|
||||
|
||||
Correct UID and GID for `app` user inside container:
|
||||
|
||||
```bash
|
||||
[root@test-podman maksym]# podman exec certs-ui-server id -u app
|
||||
1654
|
||||
[root@test-podman maksym]# podman exec certs-ui-server id -g app
|
||||
1654
|
||||
```
|
||||
|
||||
Then you have to find your `subuid` and `subgid` ranges:
|
||||
|
||||
```bash
|
||||
[<youruser>@<yourdomain> ~]$ grep $(whoami) /etc/subuid
|
||||
<youruser>:524288:65536
|
||||
[<youruser>@<yourdomain> ~]$ grep $(whoami) /etc/subgid
|
||||
<youruser>:524288:65536
|
||||
```
|
||||
|
||||
Calculate host UID and GID that maps to container's `app
|
||||
|
||||
```
|
||||
host_uid = subuid_start + container_uid
|
||||
= 524288 + 1654
|
||||
= 525942
|
||||
|
||||
host_gid = 525942
|
||||
```
|
||||
|
||||
Apply correct ownership and permissions to the volumes:
|
||||
|
||||
```bash
|
||||
sudo chown -R 525942:525942 /opt/Compose/MaksIT.CertsUI/{data,cache,acme}
|
||||
sudo chmod -R 775 /opt/Compose/MaksIT.CertsUI/{data,cache,acme}
|
||||
|
||||
sudo chown -R 525942:525942 /opt/Compose/MaksIT.CertsUI/tmp
|
||||
sudo chmod 1777 /opt/Compose/MaksIT.CertsUI/tmp
|
||||
```
|
||||
|
||||
Then run podman compose as normal user:
|
||||
|
||||
```bash
|
||||
podman compose -f docker-compose.yml up --build
|
||||
```
|
||||
@ -708,14 +609,10 @@ docker compose -f docker-compose.yml down
|
||||
|
||||
## MaksIT.CertsUI Server installation on Kubernetes
|
||||
|
||||
### 1. Add MaksIT Helm Repository
|
||||
The MaksIT.CertsUI Helm chart is distributed via the MaksIT container registry using the Helm OCI (Open Container Initiative) protocol.
|
||||
|
||||
The MaksIT.CertsUI Helm chart is available from the MaksIT container registry. Add the MaksIT Helm repository to your Helm client:
|
||||
|
||||
```bash
|
||||
helm repo add maksit https://cr.maks-it.com/chartrepo/charts
|
||||
helm repo update
|
||||
```
|
||||
**What is Helm OCI?**
|
||||
Helm OCI support enables you to pull and install Helm charts directly from container registries (such as Harbor, Docker Hub, or GitHub Container Registry), just like you would with Docker images. This approach is secure, versioned, and recommended for modern Kubernetes deployments.
|
||||
|
||||
### 2. Prepare Namespace, Secrets, and ConfigMap
|
||||
|
||||
@ -832,7 +729,7 @@ Replace all JWT-related placeholder values `<your-issuer>`, `<your-audience>` an
|
||||
|
||||
### 3. Create a Minimal Custom Values File
|
||||
|
||||
Below is a minimal example of a `custom-values.yaml` for most users. It disables image pull secrets by default (since the chart and images are public), sets the storage class for persistent volumes, and configures the reverse proxy service. You can further customize this file as needed for your environment.
|
||||
Below is a minimal example of a `custom-values.yaml` for most users. It sets the storage class for persistent volumes, and configures the reverse proxy service. You can further customize this file as needed for your environment.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
@ -845,32 +742,54 @@ components:
|
||||
|
||||
reverseproxy:
|
||||
service:
|
||||
type: LoadBalancer
|
||||
enabled: true
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
# Remove or comment out the next two lines to let your cloud provider assign a dynamic IP
|
||||
# loadBalancerIP: "172.16.0.5"
|
||||
# annotations:
|
||||
# lbipam.cilium.io/ips: "172.16.0.5"
|
||||
externalTrafficPolicy: Local
|
||||
sessionAffinity: ClientIP
|
||||
sessionAffinityConfig:
|
||||
clientIP:
|
||||
timeoutSeconds: 10800
|
||||
```
|
||||
|
||||
### 4. Install the Helm Chart
|
||||
|
||||
Install the MaksIT.CertsUI chart using your custom values file:
|
||||
Install the MaksIT.CertsUI chart using your custom values file.
|
||||
|
||||
**On Linux:**
|
||||
|
||||
```bash
|
||||
helm install certs-ui maksit/certs-ui -n certs-ui -f custom-values.yaml
|
||||
helm upgrade certs-ui oci://cr.maks-it.com/charts/certs-ui \
|
||||
-n certs-ui \
|
||||
-f custom-values.yaml \
|
||||
--version 3.3.1 \
|
||||
```
|
||||
|
||||
**On Windows PowerShell:*
|
||||
|
||||
```powershell
|
||||
helm upgrade certs-ui oci://cr.maks-it.com/charts/certs-ui `
|
||||
-n certs-ui `
|
||||
-f custom-values.yaml `
|
||||
--version 3.3.1 `
|
||||
```
|
||||
|
||||
**Note:**
|
||||
Chart version follows app version. To install a specific version, use the `--version` flag:
|
||||
|
||||
### 5. Uninstall the Helm Chart
|
||||
|
||||
To uninstall the MaksIT.CertsUI chart and remove all associated resources, run the following command:
|
||||
|
||||
**On Linux:**
|
||||
|
||||
```bash
|
||||
helm uninstall certs-ui oci://cr.maks-it.com/charts/certs-ui \
|
||||
-n certs-ui
|
||||
```
|
||||
|
||||
**On Windows PowerShell:**
|
||||
|
||||
```powershell
|
||||
helm uninstall certs-ui oci://cr.maks-it.com/charts/certs-ui `
|
||||
-n certs-ui-test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@ -929,7 +848,3 @@ For any inquiries or contributions, feel free to reach out:
|
||||
|
||||
- **Email**: maksym.sadovnychyy@gmail.com
|
||||
- **Author**: Maksym Sadovnychyy (MAKS-IT)
|
||||
|
||||
---
|
||||
|
||||
> **Tip:** For the latest updates, documentation, and source code, visit the [GitHub repository](https://github.com/MAKS-IT-COM/certs-ui).
|
||||
@ -1,31 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../README.md" Pack="true" PackagePath="" />
|
||||
<None Include="../../LICENSE.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MaksIT.Models\MaksIT.Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="build_and_deploy.sh">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -1,37 +0,0 @@
|
||||
|
||||
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
|
||||
@ -1,28 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace MaksIT.Agent.AuthorizationFilters;
|
||||
|
||||
public class ApiKeyAuthorizationFilter : IAuthorizationFilter {
|
||||
|
||||
private readonly Configuration _appSettings;
|
||||
|
||||
public ApiKeyAuthorizationFilter(
|
||||
IOptions<Configuration> appSettings
|
||||
) {
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context) {
|
||||
if (!context.HttpContext.Request.Headers.TryGetValue("X-API-KEY", out var extractedApiKey)) {
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_appSettings.ApiKey.Equals(extractedApiKey)) {
|
||||
context.Result = new UnauthorizedResult();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
namespace MaksIT.Agent {
|
||||
public class Configuration {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using MaksIT.Models.Agent.Requests;
|
||||
using MaksIT.Agent.AuthorizationFilters;
|
||||
|
||||
namespace MaksIT.Agent.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
|
||||
public class CertsController : ControllerBase {
|
||||
|
||||
private readonly Configuration _appSettings;
|
||||
private readonly ILogger<CertsController> _logger;
|
||||
|
||||
public CertsController(
|
||||
IOptions<Configuration> appSettings,
|
||||
ILogger<CertsController> logger
|
||||
) {
|
||||
_logger = logger;
|
||||
_appSettings = appSettings.Value;
|
||||
}
|
||||
|
||||
[HttpPost("[action]")]
|
||||
public IActionResult Upload([FromBody] CertsUploadRequest requestData) {
|
||||
_logger.LogInformation("Uploading certificates");
|
||||
|
||||
foreach (var (fileName, fileContent) in requestData.Certs) {
|
||||
System.IO.File.WriteAllText(Path.Combine(_appSettings.CertsPath, fileName), fileContent);
|
||||
}
|
||||
|
||||
return Ok("Certificates uploaded successfully");
|
||||
}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
using MaksIT.Agent.AuthorizationFilters;
|
||||
|
||||
namespace Agent.Controllers {
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
|
||||
public class HelloWorldController : ControllerBase {
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Get() {
|
||||
return Ok("Hello, World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using MaksIT.Agent.AuthorizationFilters;
|
||||
using MaksIT.Models.Agent.Requests;
|
||||
|
||||
namespace MaksIT.Agent.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
|
||||
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;
|
||||
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
using MaksIT.Agent;
|
||||
using MaksIT.Agent.AuthorizationFilters;
|
||||
|
||||
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();
|
||||
|
||||
builder.Services.AddScoped<ApiKeyAuthorizationFilter>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment()) {
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
@ -1,40 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"dotnetRunMessages": true,
|
||||
"applicationUrl": "http://localhost:5000"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
@ServiceReloader_HostAddress = http://localhost:5186
|
||||
|
||||
GET {{ServiceReloader_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"Configuration": {
|
||||
"ApiKey": "UGnCaElLLJClHgUeet/yr7vNvPf13b1WkDJQMfsiP6I=",
|
||||
"CertsPath": "/etc/haproxy/certs"
|
||||
}
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
#!/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 Agent.csproj --configuration Release
|
||||
sudo dotnet publish Agent.csproj -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
|
||||
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>MaksIT.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||
@ -9,11 +9,6 @@
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../README.md" Pack="true" PackagePath="" />
|
||||
<None Include="../../LICENSE.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaksIT.Core" Version="1.5.9" />
|
||||
<PackageReference Include="MaksIT.Results" Version="1.1.1" />
|
||||
|
||||
@ -5,14 +5,16 @@ VisualStudioVersion = 17.6.33815.320
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetsEncrypt", "LetsEncrypt\LetsEncrypt.csproj", "{7DE431E5-889C-434E-AD02-9F89D7A0ED27}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3374FDB1-C95E-4103-8E14-5BBF0BDC4E9D}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{3374FDB1-C95E-4103-8E14-5BBF0BDC4E9D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\LICENSE.md = ..\LICENSE.md
|
||||
..\README.md = ..\README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaksIT.Webapi", "MaksIT.Webapi\MaksIT.Webapi.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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MaksIT.Models", "MaksIT.Models\MaksIT.Models.csproj", "{6814169B-D4D0-40B2-9FA9-89997DD44C30}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReverseProxy", "ReverseProxy\ReverseProxy.csproj", "{BE051147-7AB7-4358-9C24-5CB40FAFF4FC}"
|
||||
@ -35,10 +37,6 @@ 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
|
||||
@ -1,15 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="LetsEncryptServer\CertsFlow\Responses\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaksIT.Core" Version="1.5.9" />
|
||||
</ItemGroup>
|
||||
|
||||
@ -2,7 +2,12 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicon/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="CertsUI" />
|
||||
<link rel="manifest" href="/favicon/site.webmanifest" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>MaksIT.CertsUI</title>
|
||||
</head>
|
||||
|
||||
BIN
src/MaksIT.WebUI/public/favicon/apple-touch-icon.png
Normal file
BIN
src/MaksIT.WebUI/public/favicon/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
src/MaksIT.WebUI/public/favicon/favicon-96x96.png
Normal file
BIN
src/MaksIT.WebUI/public/favicon/favicon-96x96.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
BIN
src/MaksIT.WebUI/public/favicon/favicon.ico
Normal file
BIN
src/MaksIT.WebUI/public/favicon/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
1
src/MaksIT.WebUI/public/favicon/favicon.svg
Normal file
1
src/MaksIT.WebUI/public/favicon/favicon.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 286 KiB |
21
src/MaksIT.WebUI/public/favicon/site.webmanifest
Normal file
21
src/MaksIT.WebUI/public/favicon/site.webmanifest
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "CertsUI",
|
||||
"short_name": "CertsUI",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
BIN
src/MaksIT.WebUI/public/favicon/web-app-manifest-192x192.png
Normal file
BIN
src/MaksIT.WebUI/public/favicon/web-app-manifest-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
src/MaksIT.WebUI/public/favicon/web-app-manifest-512x512.png
Normal file
BIN
src/MaksIT.WebUI/public/favicon/web-app-manifest-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 KiB |
@ -33,10 +33,12 @@ const LoginScreen: FC = () => {
|
||||
const handleLogin = () => {
|
||||
if (!formIsValid) return
|
||||
|
||||
if (formState.twoFactorCode === '') delete formState.twoFactorCode
|
||||
if (formState.twoFactorRecoveryCode === '') delete formState.twoFactorRecoveryCode
|
||||
const newFormState = { ...formState }
|
||||
|
||||
dispatch(login(formState))
|
||||
if (newFormState.twoFactorCode === '') delete newFormState.twoFactorCode
|
||||
if (newFormState.twoFactorRecoveryCode === '') delete newFormState.twoFactorRecoveryCode
|
||||
|
||||
dispatch(login(newFormState))
|
||||
}
|
||||
|
||||
const handleSubmit = (e: KeyboardEvent<HTMLDivElement>) => {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
USER app
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["MaksIT.Models/MaksIT.Models.csproj", "MaksIT.Models/"]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||
@ -11,11 +11,6 @@
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="../../README.md" Pack="true" PackagePath="" />
|
||||
<None Include="../../LICENSE.md" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MaksIT.Results" Version="1.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
|
||||
|
||||
@ -74,6 +74,24 @@ foreach ($service in $services.Keys) {
|
||||
}
|
||||
|
||||
# --- Helm Chart Release Section ---
|
||||
# Backup Chart.yaml
|
||||
Copy-Item "helm/Chart.yaml" "helm/Chart.yaml.bak" -Force
|
||||
|
||||
# Use the same tags, but choose the first non-'latest' for Helm
|
||||
$helmTag = $tags | Where-Object { $_ -ne "latest" } | Select-Object -First 1
|
||||
if (-not $helmTag) { throw "No valid SemVer tag found for Helm chart release." }
|
||||
|
||||
Write-Output "Using Helm chart version: $helmTag"
|
||||
|
||||
# Update Chart.yaml version and appVersion
|
||||
$content = Get-Content "helm/Chart.yaml" -Raw
|
||||
|
||||
$content = $content `
|
||||
-replace '(?m)^\s*version:\s*.*$', "version: $helmTag" `
|
||||
-replace '(?m)^\s*appVersion:\s*.*$', "appVersion: $helmTag"
|
||||
|
||||
Set-Content "helm/Chart.yaml" $content
|
||||
|
||||
# Package the Helm chart
|
||||
$chartDir = "helm"
|
||||
$chartPackageOutput = helm package $chartDir
|
||||
@ -85,8 +103,9 @@ if (-not $chartPackage) {
|
||||
throw "Helm chart packaging failed. Output: $chartPackageOutput"
|
||||
}
|
||||
|
||||
# Push the Helm chart to the same Harbor project/repo as Docker images
|
||||
$helmRepoUrl = "oci://$harborUrl/$projectName/charts"
|
||||
# Push the Helm chart to Harbor
|
||||
$helmRepoUrl = "oci://$harborUrl/charts"
|
||||
|
||||
Write-Output "Pushing Helm chart $chartPackage to $helmRepoUrl..."
|
||||
helm push $chartPackage $helmRepoUrl --username $harborUsername --password $harborPassword
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
@ -98,8 +117,8 @@ if ($chartPackage) {
|
||||
Write-Output "Cleaned up $chartPackage"
|
||||
}
|
||||
|
||||
# Restore Chart.yaml
|
||||
Move-Item "helm/Chart.yaml.bak" "helm/Chart.yaml" -Force
|
||||
|
||||
docker logout $harborUrl | Out-Null
|
||||
Write-Output "Completed successfully."
|
||||
|
||||
|
||||
# Logout after pushing images
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
|
||||
USER app
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["ReverseProxy/ReverseProxy.csproj", "ReverseProxy/"]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
|
||||
@ -3,28 +3,28 @@
|
||||
"Routes": {
|
||||
"well-known-acme-challenge-route": {
|
||||
"Match": { "Path": "/.well-known/acme-challenge/{**catch-all}" },
|
||||
"ClusterId": "letsencrypt-server"
|
||||
"ClusterId": "certs-ui-server"
|
||||
},
|
||||
"swagger-route": {
|
||||
"Match": { "Path": "/swagger/{**catch-all}" },
|
||||
"ClusterId": "letsencrypt-server"
|
||||
"ClusterId": "certs-ui-server"
|
||||
},
|
||||
"api-route": {
|
||||
"Match": { "Path": "/api/{**catch-all}" },
|
||||
"ClusterId": "letsencrypt-server"
|
||||
"ClusterId": "certs-ui-server"
|
||||
},
|
||||
"default-route": {
|
||||
"Match": { "Path": "{**catch-all}" },
|
||||
"ClusterId": "letsencrypt-app"
|
||||
"ClusterId": "certs-ui-client"
|
||||
}
|
||||
},
|
||||
"Clusters": {
|
||||
"letsencrypt-server": {
|
||||
"certs-ui-server": {
|
||||
"Destinations": {
|
||||
"d1": { "Address": "http://certs-ui-server:5000/" }
|
||||
}
|
||||
},
|
||||
"letsencrypt-app": {
|
||||
"certs-ui-client": {
|
||||
"Destinations": {
|
||||
"d1": { "Address": "http://certs-ui-client:5173/" }
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<ProjectGuid>0233e43f-435d-4309-b20c-ecd4bfbd2e63</ProjectGuid>
|
||||
<DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
|
||||
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}/swagger</DockerServiceUrl>
|
||||
<DockerServiceName>letsencryptserver</DockerServiceName>
|
||||
<DockerServiceName>maksit-certs-ui</DockerServiceName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="docker-compose.override.yml">
|
||||
|
||||
@ -22,15 +22,13 @@ spec:
|
||||
labels:
|
||||
{{- include "certs-ui.labels" $root | nindent 8 }}
|
||||
app.kubernetes.io/component: {{ $compName }}
|
||||
{{- if and $comp.secretsFile $comp.secretsFile.forceUpdate }}
|
||||
annotations:
|
||||
rollme: "{{$roll}}"
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- include "certs-ui.imagePullSecrets" $root | nindent 6 }}
|
||||
containers:
|
||||
- name: {{ $compName }}
|
||||
image: "{{ $comp.image.registry }}/{{ $comp.image.repository }}:{{ $comp.image.tag }}"
|
||||
image: "{{ $comp.image.registry }}/{{ $comp.image.repository }}:{{ $.Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ default "IfNotPresent" $comp.image.pullPolicy }}
|
||||
{{ $svc := default dict $comp.service }}
|
||||
{{ $tgt := default 8080 $svc.targetPort }}
|
||||
@ -46,15 +44,6 @@ spec:
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if eq $compName "client" }}
|
||||
- name: VITE_API_URL
|
||||
value: >
|
||||
{{- if eq $root.Values.components.reverseproxy.service.type "LoadBalancer" -}}
|
||||
http://{{ $root.Values.components.reverseproxy.service.loadBalancerIP }}:{{ $root.Values.components.reverseproxy.service.port }}
|
||||
{{- else -}}
|
||||
http://{{ include "certs-ui.fullname" $root }}-reverseproxy:{{ $root.Values.components.reverseproxy.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $p := default dict $comp.persistence -}}
|
||||
{{- $vols := default (list) $p.volumes -}}
|
||||
{{- $hasVols := gt (len $vols) 0 -}}
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
global:
|
||||
imagePullSecrets:
|
||||
- name: cr-maksit-pull
|
||||
imagePullSecrets: [] # Keep empty
|
||||
# imagePullSecrets:
|
||||
# - name: cr-maksit-pull
|
||||
|
||||
components:
|
||||
server:
|
||||
image:
|
||||
registry: cr.maks-it.com
|
||||
repository: certs-ui/server
|
||||
tag: latest
|
||||
pullPolicy: Always
|
||||
env:
|
||||
- name: ASPNETCORE_ENVIRONMENT
|
||||
value: Development
|
||||
value: Production
|
||||
- name: ASPNETCORE_HTTP_PORTS
|
||||
value: "5000"
|
||||
service:
|
||||
@ -57,7 +57,7 @@ components:
|
||||
},
|
||||
}
|
||||
keep: true
|
||||
forceUpdate: false
|
||||
|
||||
configMapFile:
|
||||
key: appsettings.json
|
||||
mountPath: /configMap/appsettings.json
|
||||
@ -93,47 +93,43 @@ components:
|
||||
}
|
||||
}
|
||||
keep: true
|
||||
forceUpdate: false
|
||||
|
||||
client:
|
||||
image:
|
||||
registry: cr.maks-it.com
|
||||
repository: certs-ui/client
|
||||
tag: latest
|
||||
pullPolicy: Always
|
||||
env:
|
||||
- name: ASPNETCORE_ENVIRONMENT
|
||||
value: Development
|
||||
service:
|
||||
enabled: true
|
||||
type: ClusterIP
|
||||
port: 5173
|
||||
targetPort: 5173
|
||||
|
||||
|
||||
reverseproxy:
|
||||
image:
|
||||
registry: cr.maks-it.com
|
||||
repository: certs-ui/reverseproxy
|
||||
tag: latest
|
||||
pullPolicy: Always
|
||||
env:
|
||||
- name: ASPNETCORE_ENVIRONMENT
|
||||
value: Development
|
||||
value: Production
|
||||
- name: ASPNETCORE_HTTP_PORTS
|
||||
value: "8080"
|
||||
service:
|
||||
enabled: true
|
||||
type: LoadBalancer
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
loadBalancerIP: "172.16.0.5"
|
||||
annotations:
|
||||
lbipam.cilium.io/ips: "172.16.0.5"
|
||||
labels:
|
||||
export: "bgp"
|
||||
externalTrafficPolicy: Local
|
||||
sessionAffinity: ClientIP
|
||||
sessionAffinityConfig:
|
||||
clientIP:
|
||||
timeoutSeconds: 10800
|
||||
# type: LoadBalancer
|
||||
# port: 8080
|
||||
# targetPort: 8080
|
||||
# loadBalancerIP: "172.16.0.5"
|
||||
# annotations:
|
||||
# lbipam.cilium.io/ips: "172.16.0.5"
|
||||
# labels:
|
||||
# export: "bgp"
|
||||
# externalTrafficPolicy: Local
|
||||
# sessionAffinity: ClientIP
|
||||
# sessionAffinityConfig:
|
||||
# clientIP:
|
||||
# timeoutSeconds: 10800
|
||||
Loading…
Reference in New Issue
Block a user