A distributed, security-first microservice platform for automated Active Directory management.
Self-service password resets via Telegram — fully auditable, zero-trust, enterprise-grade.
- Overview
- Key Features
- System Architecture
- Technology Stack
- Security Model
- Observability
- Getting Started
- Component Documentation
- Contributing
itSolutionsNow (ISN) solves a common enterprise pain point: IT helpdesk overloaded with password reset requests that require no human decision — only identity verification and a privileged AD operation.
ISN automates this workflow end-to-end:
- An employee initiates a reset via Telegram — no VPN, no special client required.
- The system verifies identity through an out-of-band channel and validates the request.
- A Windows service with gMSA credentials executes the privileged AD operation — no human in the loop.
- Every step is traced end-to-end with a unique
TraceID, fully auditable via Jaeger.
The result: zero helpdesk tickets for password resets, zero standing privileged sessions, and a complete audit trail for compliance.
| Feature | Description |
|---|---|
| Self-service password reset | Employees reset their own AD passwords via Telegram, 24/7 |
| Out-of-band verification | Telegram as the identity verification channel, separate from corporate network |
| Zero-trust messaging | All inter-service communication via RabbitMQ with mutual TLS — no direct HTTP between services |
| Privileged AD execution | Windows agent uses gMSA — no stored credentials, no service account passwords |
| Kerberos SSO for admins | Admin Portal integrates with domain SSO — no separate credentials |
| PII protection | Phone numbers and logins hashed (SHA-256 + global salt) before storage and tracing |
| Full distributed tracing | TraceID propagates from Telegram message to AD operation — visible in Jaeger |
| Segmented observability | Metrics (VictoriaMetrics), traces (Jaeger), logs — unified through OTel Collector |
ISN is built on a three-node physical topology mapped to four logical trust zones. Services never communicate via direct HTTP — all inter-service messaging flows through the RabbitMQ broker over mTLS.
┌─────────────────────────────────────────────────────────────────────┐
│ PUBLIC INTERNET │ VENDOR (TELEGRAM) │
│ End users, zero trust │ Bot API, partial trust │
└───────────────┬───────────┴──────────────┬──────────────────────────┘
│ HTTPS/TLS │ HTTPS/TLS
┌───────────────▼──────────────────────────▼──────────────────────────┐
│ DMZ / GATEWAY │
│ srv-isn-gw · 192.168.10.200 │
│ [ isn-tg-agent · Python 3.12 · Aiogram ] │
└───────────────────────────────┬─────────────────────────────────────┘
│ mTLS · AMQP 5671
┌───────────────────────────────▼─────────────────────────────────────┐
│ SECURED INTERNAL SEGMENT ◄── RED: critical perimeter │
│ │
│ srv-isn-core · 192.168.10.201 │
│ ┌─────────────────┐ ┌──────────────────┐ ┌───────────────────┐ │
│ │ isn-admin-portal│ │isn-identity-svc │ │ infra-bus │ │
│ │ .NET 9 Blazor │ │ .NET 9 Worker │ │ RabbitMQ 4.0 │ │
│ │ :8081 │ │ State Orchestr. │ │ mTLS enforced │ │
│ └─────────────────┘ └──────────────────┘ └───────────────────┘ │
│ ┌─────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ infra-db │ │ Observability: OTel · Jaeger · VM │ │
│ │ PostgreSQL 17 │ │ PII masking at Collector level │ │
│ └─────────────────┘ └──────────────────────────────────────────┘ │
│ │
│ app01 · 192.168.10.125 · Windows Server │
│ [ isn-ad-agent · .NET 9 Worker · gMSA · Host Network ] │
│ [ dc02 · Active Directory Domain Controller ] │
└─────────────────────────────────────────────────────────────────────┘
The diagram below shows the full network topology: trust zones, physical servers, and cross-zone data flows with protocols and ports.
%%{init: {
"theme": "dark",
"themeVariables": {
"primaryColor": "#1a2a3a",
"primaryTextColor": "#c8d8e8",
"primaryBorderColor": "#4488bb",
"lineColor": "#7799bb",
"secondaryColor": "#1e2a1e",
"tertiaryColor": "#1a1a2e",
"clusterBkg": "#12121e",
"clusterBorder": "#445566",
"edgeLabelBackground": "#1a1a2e",
"fontSize": "14px"
}
}}%%
graph TD
subgraph Internet_Zone ["PUBLIC INTERNET"]
Employee(["End user\n(Telegram App)"])
end
subgraph Vendor_Zone ["VENDOR: TELEGRAM CLOUD"]
TG_API["Telegram Bot API\nHTTPS · Port 443"]
end
subgraph DMZ_Zone ["DMZ / GATEWAY SEGMENT"]
subgraph srv_gw ["srv-isn-gw · 192.168.10.200"]
TG_Agent["isn-tg-agent\nPython 3.12 · Aiogram\n172.24.0.5"]
end
end
subgraph Secured_Zone ["SECURED INTERNAL SEGMENT"]
subgraph srv_core ["srv-isn-core · 192.168.10.201"]
Portal["isn-admin-portal\n.NET 9 Blazor · :8081"]
Identity["isn-identity-service\n.NET 9 Worker"]
Bus["infra-bus\nRabbitMQ 4.0\nVHosts: isn-inbound, isn-exec"]
DB["infra-db\nPostgreSQL 17"]
Observability["Observability Stack\nOTel · Jaeger · VictoriaMetrics"]
end
subgraph win_node ["app01 · 192.168.10.125 · Windows Server"]
AD_Agent["isn-ad-agent\n.NET 9 Worker\ngMSA · Host Network"]
end
subgraph ad_infra ["Active Directory Infrastructure"]
DC["dc02\nActive Directory\nDomain Controller"]
end
Admin(["IT Administrator"])
end
Employee <-->|"HTTPS / TLS · 443"| TG_API
TG_API <-->|"HTTPS / TLS · 443"| TG_Agent
TG_Agent <-->|"mTLS · AMQP 5671"| Bus
TG_Agent -.->|"OTLP/HTTPS · 4317"| Observability
Admin ==>|"Kerberos SSO\nGSSAPI LDAP"| Portal
Portal <-->|"mTLS · AMQP 5671"| Bus
Identity <-->|"mTLS · AMQP 5671"| Bus
Identity <-->|"TLS · 5432"| DB
Portal --- Identity
AD_Agent <-->|"mTLS · AMQP 5671"| Bus
AD_Agent -.->|"OTLP/HTTPS · 4317"| Observability
AD_Agent ==>|"AD RPC / LDAP\ngMSA SetPassword"| DC
style Internet_Zone fill:#1a1a1a,stroke:#777777,stroke-width:1.5px,stroke-dasharray:6 3,color:#999999
style Vendor_Zone fill:#0d1525,stroke:#4477cc,stroke-width:1.5px,stroke-dasharray:6 3,color:#7799cc
style DMZ_Zone fill:#1e1500,stroke:#cc8800,stroke-width:2px,stroke-dasharray:6 3,color:#cc9922
style Secured_Zone fill:#1e0505,stroke:#cc3333,stroke-width:2.5px,stroke-dasharray:6 3,color:#cc5555
style srv_gw fill:#12121e,stroke:#445566,stroke-width:1.5px,color:#aabbcc
style srv_core fill:#12121e,stroke:#445566,stroke-width:1.5px,color:#aabbcc
style win_node fill:#0d1a0d,stroke:#446644,stroke-width:1.5px,color:#88aa88
style ad_infra fill:#0d1a0d,stroke:#446644,stroke-width:1.5px,color:#88aa88
style TG_Agent fill:#1a1a0d,stroke:#aaaa00,stroke-width:1.5px,color:#eeee88
style Portal fill:#0d1f3a,stroke:#4488cc,stroke-width:1.5px,color:#aaccff
style Identity fill:#0d1f3a,stroke:#4488cc,stroke-width:1.5px,color:#aaccff
style Bus fill:#1a0d1a,stroke:#9944cc,stroke-width:1.5px,color:#cc88ff
style DB fill:#1a0d1a,stroke:#9944cc,stroke-width:1.5px,color:#cc88ff
style Observability fill:#0d1a1a,stroke:#44aaaa,stroke-width:1.5px,color:#88dddd
style AD_Agent fill:#0d2a0d,stroke:#44aa44,stroke-width:1.5px,color:#88ee88
style DC fill:#0d2a0d,stroke:#44aa44,stroke-width:1.5px,color:#88ee88
style TG_API fill:#0d1525,stroke:#3366aa,stroke-width:1.5px,color:#88aaee
style Employee fill:#1e1e1e,stroke:#666666,stroke-width:1.5px,color:#bbbbbb
style Admin fill:#1e1e1e,stroke:#666666,stroke-width:1.5px,color:#bbbbbb
This diagram shows how containers inside
srv-isn-corecommunicate — Docker subnet, RabbitMQ VHost segmentation, and the full observability pipeline.
%%{init: {
"theme": "dark",
"themeVariables": {
"primaryColor": "#1a2a3a",
"primaryTextColor": "#c8d8e8",
"primaryBorderColor": "#4488bb",
"lineColor": "#7799bb",
"clusterBkg": "#12121e",
"clusterBorder": "#445566",
"edgeLabelBackground": "#1a1a2e",
"fontSize": "13px"
}
}}%%
graph LR
ExtGW(["isn-tg-agent\nGateway · 172.24.0.5"])
ExtAD(["isn-ad-agent\napp01 · Host Net"])
ExtAdmin(["Admin\nKerberos SSO"])
subgraph Core_Server ["srv-isn-core · 192.168.10.201 · Docker 172.24.0.0/16"]
subgraph Bus_Block ["infra-bus · RabbitMQ 4.0 · 172.24.0.3"]
VH_IN["VHost: isn-inbound\n(user events, portal commands)"]
VH_EX["VHost: isn-exec\n(AD execution tasks)"]
end
Portal["isn-admin-portal\n.NET 9 Blazor\n172.24.0.10 · :8081"]
Identity["isn-identity-service\n.NET 9 Worker\n172.24.0.11"]
DB["infra-db\nPostgreSQL 17\n172.24.0.2"]
subgraph Obs_Block ["Observability Pipeline"]
OTel["infra-otel-collector\nOTel Collector\n172.24.0.20\nPII masking · SHA256"]
Jaeger["infra-jaeger\nJaeger\n172.24.0.21\nDistributed Tracing UI"]
VM["infra-victoriametrics\nVictoriaMetrics\n172.24.0.22\nMetrics & Logs TSDB"]
end
end
ExtGW -->|"mTLS · AMQP 5671\npublish → isn-inbound"| VH_IN
ExtAdmin ==>|"Kerberos SSO"| Portal
Portal <-->|"mTLS · AMQP 5671"| VH_IN
Portal -->|"TLS · 5432"| DB
Identity <-->|"mTLS · AMQP 5671"| VH_IN
Identity -->|"mTLS · AMQP 5671\npublish → isn-exec"| VH_EX
Identity <-->|"TLS · 5432"| DB
VH_EX -->|"mTLS · AMQP 5671\nconsume"| ExtAD
Portal -.->|"OTLP/gRPC · 4317"| OTel
Identity -.->|"OTLP/gRPC · 4317"| OTel
DB -.->|"OTLP · 4317"| OTel
ExtGW -.->|"OTLP/HTTPS · 4317"| OTel
ExtAD -.->|"OTLP/HTTPS · 4317"| OTel
OTel -->|"Traces"| Jaeger
OTel -->|"Metrics & Logs"| VM
style Core_Server fill:#1e0505,stroke:#cc3333,stroke-width:2.5px,stroke-dasharray:6 3,color:#cc5555
style Bus_Block fill:#120d1a,stroke:#9944cc,stroke-width:1.5px,color:#cc88ff
style Obs_Block fill:#0d1a1a,stroke:#44aaaa,stroke-width:1.5px,color:#88dddd
style Portal fill:#0d1f3a,stroke:#4488cc,stroke-width:1.5px,color:#aaccff
style Identity fill:#0d1f3a,stroke:#4488cc,stroke-width:1.5px,color:#aaccff
style VH_IN fill:#1a0d1a,stroke:#9944cc,stroke-width:1.5px,color:#cc88ff
style VH_EX fill:#1a0d1a,stroke:#9944cc,stroke-width:1.5px,color:#cc88ff
style DB fill:#1a0d1a,stroke:#9944cc,stroke-width:1.5px,color:#cc88ff
style OTel fill:#0d1a1a,stroke:#44aaaa,stroke-width:1.5px,color:#88dddd
style Jaeger fill:#0d1a1a,stroke:#44aaaa,stroke-width:1.5px,color:#88dddd
style VM fill:#0d1a1a,stroke:#44aaaa,stroke-width:1.5px,color:#88dddd
style ExtGW fill:#1e1e1e,stroke:#666,stroke-width:1.5px,color:#bbb
style ExtAD fill:#1e1e1e,stroke:#666,stroke-width:1.5px,color:#bbb
style ExtAdmin fill:#1e1e1e,stroke:#666,stroke-width:1.5px,color:#bbb
| Layer | Component | Technology | Version |
|---|---|---|---|
| Gateway | Telegram Agent | Python · Aiogram · Aio-pika | 3.12 |
| Portal | Admin Web UI | .NET · Blazor · EF Core | 9.0 |
| Core | Identity & Orchestration | .NET Worker Service | 9.0 |
| Execution | AD Agent | .NET Worker · AccountManagement | 9.0 |
| Messaging | Event Bus | RabbitMQ (mTLS, segmented VHosts) | 4.0 |
| Database | Primary Store | PostgreSQL (TLS, encrypted volume) | 17 |
| Tracing | Distributed Tracing | OpenTelemetry + Jaeger | latest |
| Metrics | Time-Series DB | VictoriaMetrics | latest |
| Telemetry | Collector + PII masking | OpenTelemetry Collector | latest |
| Auth | Admin SSO | Kerberos / GSSAPI LDAP | — |
| AD Auth | Service Account | gMSA (Group Managed Service Account) | — |
| Runtime | Containers | Docker + Docker Compose | — |
ISN is designed with a defense-in-depth posture. Each layer adds an independent security control.
All inter-service communication flows through RabbitMQ over mutual TLS (mTLS) on port 5671. No service exposes an HTTP endpoint to other services. There is no way to bypass the broker.
RabbitMQ uses segmented VHosts:
| VHost | Direction | Purpose |
|---|---|---|
isn-inbound |
Gateway → Identity, Portal → Identity | User events and admin commands |
isn-exec |
Identity → AD Agent | Privileged execution tasks |
The AD Agent runs on a Windows server using a Group Managed Service Account (gMSA). This means:
- No stored passwords — the domain controller rotates credentials automatically
- The agent never holds a long-lived privileged token
SetPasswordoperations are performed in the gMSA security context
Personal data is protected at two levels:
| Level | Mechanism | Applied to |
|---|---|---|
| Storage | SHA-256 hash + global salt | Phone numbers before DB write |
| Tracing | Pseudonymization at Collector | Logins in trace spans, before Jaeger export |
This ensures PII never appears in logs, traces, or metrics — only in the encrypted database under a one-way hash.
The Admin Portal authenticates via Kerberos SSO using the domain identity of the operator. No separate credential store. Active Directory group membership controls authorization.
Every user action generates a unique TraceID that propagates through the entire system — from the initial Telegram message to the final AD operation. The full path is visible in Jaeger.
Employee → Telegram → isn-tg-agent → RabbitMQ → isn-identity-service
↓
isn-ad-agent → Active Directory
↓
TraceID closes in Jaeger
All services export telemetry exclusively through the OTel Collector — no direct backend connections from application code.
[any service] ──OTLP/gRPC:4317──► [infra-otel-collector]
│ PII masking (SHA256)
┌────┴────┐
▼ ▼
[Jaeger] [VictoriaMetrics]
(traces) (metrics & logs)
| Signal | Backend | Use case |
|---|---|---|
| Traces | Jaeger | End-to-end request lifecycle, bottleneck analysis |
| Metrics | VictoriaMetrics | Infrastructure health, SLOs, alerting |
| Logs | VictoriaMetrics | Structured application logs via OTLP |
Before deployment, ensure the following are in place:
| Requirement | Details |
|---|---|
| Three target servers | srv-isn-gw (Linux), srv-isn-core (Linux), app01 (Windows Server) |
| Docker + Docker Compose | Installed on both Linux servers |
| Internal PKI | CA capable of issuing mTLS and HTTPS certificates for all services |
| Active Directory | Domain Services environment with a gMSA provisioned for the AD Agent |
| Telegram Bot | Bot token from @BotFather |
| Network routing | srv-isn-gw reachable from Telegram; app01 reachable from srv-isn-core on port 5671 |
The system ships with an interactive deployment wizard in the /deployment directory that guides you through certificate generation, environment configuration, and service startup.
cd deployment
# Follow the interactive wizard
./setup.shFor the full step-by-step guide including PKI setup, gMSA configuration, and RabbitMQ VHost provisioning:
Each component has its own README covering configuration, environment variables, and operational notes.
| Component | Role | Stack | Docs |
|---|---|---|---|
isn-admin-portal |
Web UI for IT operators | .NET 9 Blazor | README |
isn-identity-service |
Workflow orchestration & state | .NET 9 Worker | README |
isn-tg-agent |
Telegram gateway & user interaction | Python 3.12 | README |
isn-ad-execution-agent |
Privileged AD operations | .NET 9 Worker + gMSA | README |
Contributions are welcome. Please open an issue before submitting a pull request for any significant change, so the approach can be discussed first.
When adding a new service:
- Place it in the appropriate trust zone (see Security Model)
- Route all inter-service communication through RabbitMQ — no direct HTTP
- Export telemetry via OTLP to
infra-otel-collectoronly — no direct backend connections - Update the architecture diagrams in
docs/diagrams/
Built with a focus on security, auditability, and zero operational overhead for password resets.