Skip to content

XenPool/ipsolis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

509 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ip·Solis

Source-available platform for IT asset lifecycle automation. Built for on-premises datacenters, replacing expensive commercial tools.

Give your users a self-service portal to request, extend, and return IT assets (VDIs, application access, infrastructure resources) while your IT team keeps full control through configurable approval workflows, runbooks, and audit trails.

Licensing

ip·Solis is source-available under the XenPool Commercial Source License v1.0.

  • Free tier — productive use for up to 25 active users, including in a commercial, governmental or other organizational context. No license key required. (An active user is a distinct person — by email — holding at least one active asset request/assignment; ended ones don't count.)
  • Free use — also purely private use by individuals, and non-productive research/teaching at state-recognized educational institutions.
  • Evaluation — 30 days free in any environment, no license key required.
  • Commercial use — productive use with more than 25 active users requires a valid license purchased from XenPool GmbH, offered in volume bands by active-user count (e.g. 26–75, 76–250, 250+) — regardless of profit intent, and including public-sector bodies and non-profit / charitable organizations. Get a license at the ip·Solis license shop.

All features ship in a single image — the tiers differ only by active-user count, never by features.

Why This Exists

Enterprise IT automation shouldn't require a 6-month implementation project and a six-figure license. This platform was born from 30 years of datacenter operations experience and is designed to be deployed in an afternoon.

Key Features

Self-Service Portal

  • Users request assets through a clean web interface
  • Single sign-on via OpenID Connect — Entra ID, Okta, Ping, Google, Keycloak, … (any compliant IdP)
  • Order tracking with real-time status updates
  • "My IT" dashboard showing active assets with extend/modify/cancel options
  • Deputy support (order on behalf of another user)
  • Multi-language UI (English, German, Spanish, French, Italian)
  • Catalog search and category filter in the request page (auto-shown for catalogs with more than ~6 definitions)
  • Long-form help text per asset definition (admin-authored markdown, sanitized) shown when the requester picks a type

Approval Workflows

  • Configurable per asset type: manager approval, application owner approval, or both
  • Manager looked up automatically from Active Directory
  • Re-approval on asset modification (optional per asset type)
  • Email notifications to approvers with one-click approve/decline
  • Microsoft Teams approval cards — Adaptive Card delivered via Workflows webhook with a tokenized link that lets approvers decide without logging into the portal
  • Approval reminders — a Beat task re-sends email + Teams notification after a configurable interval (default 24 h, capped at 3 nudges) when an approver hasn't decided
  • Approval delegation (OOO mode) — admins configure deputy windows ("Stefan is on vacation Aug 1–15, route his approvals to Jupp"); new orders during the window automatically address the deputy, original assignee captured in the audit trail
  • Self-service delegation in the portal — managers configure their own OOO without going through an admin (/portal/delegations); identity is enforced server-side so a user can never re-route someone else's approvals
  • Approval escalation — once an approval has burned through all its reminders without a decision, the configured escalation contact(s) get notified. Two modes: notify-only (default) emails the contact pointing at the admin UI for operational intervention; assignment mode (opt-in via approval.escalation_assign=true) creates a new OrderApproval row per contact with a tokenized one-click /approve/<token> URL so the contact can decide directly from their inbox. Each original approval escalates at most once
  • N-of-M approvals — set min_approvals_required per asset definition so any N of M configured approvers can satisfy the order. Per-rule N-of-M lets each conditional rule carry its own quorum; rule-driven approvers form an isolated group with that quorum, while manager / owner / no-quorum-rule approvers fold into the asset-type-level group. Per-bucket supersession auto-closes surplus pending rows in a bucket the moment its quorum is met (decision-time, not Beat-tick-time) so approvers in 2-of-5 groups don't keep getting reminders after the first two say yes; the whole-order supersession path still fires when every bucket meets. Decline still vetoes regardless of N
  • Conditional approval rules — JSONB rule list per asset definition adds extra approvers when a condition matches the order. Conditions can be a leaf {field, op, value} or a compound {op: "and"|"or"|"not", clauses: [...]} — nested up to 8 levels deep. Built-in fields (duration_days, monthly_cost, has_pii/phi/pci, requester_department) plus any attr.<key> from the asset type's user-supplied attributes. Visual recursive editor in the asset-type form: each compound renders an AND/OR/NOT op selector + child clauses; each leaf gets a "wrap in group" affordance; depth-coloured left borders make the tree structure obvious at a glance. Malformed rules are logged and skipped, never blocking order creation.
  • Per-classification approval routing — one-click toggle per data class (PII / PHI / PCI). Two routing modes: Compliance officer (centralised) auto-adds one approval step at the global compliance-officer email (standard for centralised compliance teams); Owner of record auto-adds one step per entry in the asset type's approval_owners list (standard for HIPAA-style workflows where the data steward who actually owns the regulated surface must sign off). Strictest-first precedence (PCI > PHI > PII), de-duped against manager / app-owner / rule approvers
  • Auto-decline on extended inactivity — opt-in policy that system-declines pending approvals past a configurable age (e.g. 14 days) so stale requests don't pile up forever. Daily Beat task picks at most one stale approval per order, propagates the existing veto-on-decline semantics (order → rejected, requester emailed, audit row attributed to system:auto_decline). Off by default; configure under Settings → E-Mail → Approval Reminders → Auto-decline (opt-in).

Dynamic Runbook Engine

  • Visual runbook builder in the Admin UI
  • Three automation strategies: Group Access (AD/Entra groups), Runbook (PowerShell scripts), or Composite (both)
  • PowerShell module management (install from Gallery or upload custom .zip) with a per-module Linux compatibility flag (Linux ✓ / Windows only ✕ / Unverified ?) — the worker runs PowerShell 7 on Linux, and modules tagged PSEdition_Desktop only won't load. Operators declare compatibility when adding a module and can flip the badge inline by clicking it in the modules table
  • In-app PowerShell script editor with parameter introspection
  • Step-by-step execution tracking with structured JSON logs

Standalone Runbooks

  • Ad-hoc or cron-scheduled runbooks that are not tied to an asset type
  • Per-run tracking (history, logs, notes)
  • Useful for housekeeping jobs, one-off operations, and scheduled reports

Asset Lifecycle Management

  • Three assignment models: capacity-pooled (quotas), dedicated-shared (jump hosts), assigned-personal (1:1)
  • Automatic expiry checks and reminder emails (Celery Beat)
  • Configurable deprovision policies: access removal, return-to-pool, return-to-pool-with-reinstall, deallocation, deletion, or custom runbook
  • Extended asset statuses — Free, In use, Reinstall, Reinstalling, Failed, Maintenance
  • Scheduled orders (future-dated provisioning with asset reservation)

Maintenance & Operations

  • Scheduled PostgreSQL backups (cron-driven) with retention policy
  • Manual backup/restore/download via Admin UI
  • Health probes (DB, Redis, Beat leader liveness, external system reachability, SIEM streaming) with email alerts on state transitions; /health is the unauthenticated load-balancer endpoint and /admin/maintenance/health is the auditor-readable detailed view
  • Celery queue inspection and targeted purge
  • Audit Log viewer at /ui/audit-log — filterable by entity type, entity id, triggered-by substring, and time range; coloured actor badges show at a glance whether each row was driven by a bearer token, an admin session, the legacy X-Admin-Key, or a webhook; expand any row to see the JSON before/after diff

Access Control

  • Restrict asset types to specific AD groups (eligible requestors)
  • Per-asset-type configuration for RDP and admin user management
  • Capacity enforcement with pool availability checks
  • Per-user quota (max_per_user) for personal and pooled assignment models so one user can't exhaust the pool
  • Active / inactive flag on asset definitions — deprecate without losing history; inactive types disappear from the portal catalog but stay visible in the admin list

Observability

  • Prometheus /metrics endpoint — request count + latency histogram per route, plus business gauges (orders by status, pending approvals, pool free/busy by asset type, Celery queue depth per worker queue)
  • Cardinality-bounded route labels (path templates, not actual paths)
  • Toggleable via the metrics.enabled config flag
  • OpenTelemetry tracing — auto-instrumented FastAPI requests, SQLAlchemy queries, and Celery tasks flow through an OTLP HTTP exporter to any standard collector (Jaeger, Tempo, SigNoz, Honeycomb); a request that dispatches a runbook produces a single trace spanning api + worker; a console exporter mode is available for local verification without a collector

HR Feed & SCIM 2.0

  • Unified leaver flow — when a user leaves, ip·Solis revokes every active order owned by them, supersedes their pending approvals (so quorum logic doesn't stall), and supersedes any pending certification reviews assigned to them. Same code path regardless of how the signal arrives. Audit trail in hr_leaver_events with per-action counts; admin viewer at /ui/leaver-events
  • HR webhook at POST /hr/leaver with HMAC fallback or scoped bearer token (hr:leaver). Adapters for ipSolis-native, Workday (workerId + eventType: terminated), SAP SuccessFactors (PERSON.PERNR), and Microsoft Graph subscription notifications (resourceData.userPrincipalName)
  • SCIM 2.0 endpoint at /scim/v2/* — leaver-focused subset of RFC 7644 (ServiceProviderConfig, ResourceTypes, Schemas, Users CRUD). DELETE and PATCH active=false trigger the leaver flow. Bearer-only auth via scim:read / scim:write scopes — drop-in target for Okta / SailPoint / Ping deprovisioning workflows

Access Reviews & Certifications

  • Access certification campaigns — required for ISO 27001 / SOX / PCI compliance audits. Create a campaign with a scope filter (asset types / cost centers / departments / requester emails), kick it off to materialise one review row per (matching order, reviewer = the order's manager). Reviewers get a kickoff email + Teams card with a signed-token URL that opens a no-login review queue. Per row they pick Confirm (user keeps access) or Revoke (ip·Solis pulls access immediately via the deprovision runbook). Daily Beat task fires reminders at configurable offsets (default T-7d / T-1d), an overdue email past due, an escalation summary to a contact list, and auto-revoke on overdue (opt-in) so unreviewed access is pulled automatically. Manager portal page at /portal/certifications for SSO users; admin drill-down at /ui/certifications with per-status counts and inline confirm/revoke for stand-in scenarios

Compliance & Audit

  • SIEM audit-log streaming (Splunk HEC + Microsoft Sentinel + generic HMAC-signed webhook) — every audit_log row is forwarded once a minute to one of four back-ends: Splunk HTTP Event Collector, Sentinel via the legacy Azure Monitor Data Collector API (sunset by Microsoft on 2026-08-31 — kept for back-compat), Sentinel via the newer Logs Ingestion API (DCE / DCR + AAD service principal — recommended for new deployments), or a generic JSON webhook with HMAC-SHA256 body signing in a GitHub-compatible X-Hub-Signature-256: sha256=<hex> header (configurable header name + extra headers for receivers like Datadog, Sumo, Loki, Elastic). Persistent cursor, automatic retry on transient failure, and a "Send Test Event" button verifies connectivity before enabling
  • Tamper-evident audit log — BEFORE-statement triggers on the audit_log table block DELETE / UPDATE / TRUNCATE by default; a documented SET LOCAL ipsolis.allow_audit_mutation = 'true' escape hatch exists for legitimate retention maintenance
  • Audit retention pruning — daily Beat task auto-deletes audit rows older than the configured window using the bypass GUC. Per-classification windows (retention.pii_days, retention.phi_days, retention.pci_days) sit on top of the global retention.audit_log_days so PII/PHI/PCI rows can be kept 7+ years while routine config changes drop after 90 days. Each row's classification is set at write time from the strictest class declared on the touched asset type's attributes; last_run_at, last_pruned, and a per-class breakdown (last_pruned_by_class) are tracked in app_config for ops visibility
  • Per-integration API tokens — replaces the single shared X-Admin-Key with named, expiring, revocable bearer tokens stored as SHA-256 hashes (raw token shown once on creation); legacy X-Admin-Key still accepted as a fallback so existing integrations don't break on upgrade. Hard-delete retention policy (opt-in, api_tokens.purge_after_days): a daily Beat task hard-deletes tokens whose revoked_at or expires_at is older than the configured window, with a per-row api_token / hard_deleted audit row capturing name + prefix + reason. Default 0 keeps slice-1 retain-forever behaviour for installs that prefer the audit-trail intact
  • Admin RBAC — five-tier role ladder (superadmin > admin > approver > auditor > helpdesk) backed by per-user accounts in admin_users (PBKDF2-SHA256 / 600k iterations, stdlib-only, no bcrypt/passlib build dependency). First-run setup auto-prompts for the first superadmin when the table is empty. Self-protection guards prevent superadmin self-demotion / self-deactivation / self-delete and block losing the last active superadmin. Legacy ADMIN_API_KEY continues to authenticate as a virtual superadmin so existing scripts don't break. Audit attribution carries the role (admin:session:alice:superadmin) so auditors can filter by both who and with what authority. Comprehensive role gating: operational routers (modules, runbooks, maintenance, approval-delegations, asset-type CRUD, config writes) require admin+; infrastructure routers (license, seed export, initial setup, API tokens, admin user mgmt) require superadmin; cost-report is auditor+
  • Per-asset-type ACL grants — scope individual admin users to a subset of asset types. Granting an admin even one type flips them into "see only granted types" mode (the admin UI list filters automatically and out-of-scope PUT/DELETE/clone returns 404 — same shape as a missing id, so the existence of unrelated teams' types isn't leaked). Zero grants = back-compat "see all" so single-team installs aren't surprised by the new feature. superadmin / approver / auditor / helpdesk always bypass scoping. Auto-grant on create: when a scoped admin creates a new asset type, the grant is added automatically so they don't lose visibility on their own creation
  • Separation of duties (SoD) — a user who configured an asset type cannot also approve their own access requests against it. Detection walks the audit log for matching created / updated / cloned rows attributed to the approver (matched on email, local-part, or admin username). Fires on approve only — declines stay open since rejecting your own work is always allowed. The blocked approver gets HTTP 409 with the original config-time audit attribution quoted back, and the approval row stays pending so a different approver can decide
  • Bearer-token role binding — API tokens may be issued with a specific role (superadmin / admin / approver / auditor / helpdesk) on top of their scopes. Role-gated routes consult the token's role too, so a token with admin:* scope but auditor role gets blocked from operational writes. Tokens issued without a role keep pre-slice-3 scope-only behaviour (back-compat). Mint guard: a creator can only issue tokens at or below their own role — no privilege escalation via token issuance
  • Self-service password change — every admin user can rotate their own password via My Account (/ui/my-account). Requires the current password as a liveness check; new password must differ from the current and be ≥12 chars. Legacy ADMIN_API_KEY actors get a clear 409 directing them to rotate via .env. Audit row is password_changed_self with no value content
  • External secret management (HashiCorp Vault + CyberArk CCP/AIM + Azure Key Vault + AWS Secrets Manager + CyberArk Conjur) — replace plaintext credentials in app_config with references to your secret store. Any secret-typed config row whose value is vault://<path>[#<field>], ccp://[<safe>/]<object>, azurekv://<vault>/<secret>, awssm://<secret-id>[#<field>], or conjur://<identifier>[#<field>] is resolved at read time via the configured backend. Plain string values keep working unchanged so partial migrations are safe. Process-local TTL cache (default 60s) avoids hammering the backend on every config read. All is_secret=true config keys flow through the resolver — AD bind, Entra client secret, SMTP password, vSphere/XenServer/SCCM passwords, Teams webhook, Splunk HEC token, Sentinel shared key + Logs Ingestion SPN secret, generic-webhook HMAC secret, Conjur api_key, etc. UI shows reference-shaped values in clear (the path isn't sensitive) so admins can see which store entry each row points to. Vault auth: static token (legacy / lab), AppRole (role_id + secret_id), or Kubernetes (projected service-account JWT) — short-lived tokens cached with auto-refresh before lease expiry. CCP auth: AppID + IP allow-list or optional mTLS via configured client cert (Settings UI offers a guided cert + key file-upload form, with PEM-shape validation that catches encrypted keys / swapped files before the resolver). Azure KV auth: Azure AD service principal — independent of the Entra ID SSO config so the KV SPN carries minimum-necessary Key Vault Secrets User access. AWS Secrets Manager auth: static IAM keys (long-lived or STS-issued temporaries) or native AssumeRole — ip·Solis itself calls sts:AssumeRole with a bootstrap IAM identity and refreshes the derived session credentials automatically before Expiration. Conjur auth: host API-key login with cached short-lived access tokens (works against on-prem Conjur and Conjur Cloud). One-shot bulk-migration tool at Settings → Compliance → External Secret Backend → Migrate plaintext secrets to backend: walks every is_secret=true row, pushes the plaintext value to the active backend, and replaces the row with the matching reference. Dry-run preview + per-row report; CCP rejected with a clear error since CyberArk Safes are managed via PVWA, not the AIM API
  • HA Celery Beat scheduler — drop-in celery-redbeat swap moves the schedule into Redis with a Lua-script distributed lock. Run docker compose up -d --scale beat=N and only the lock-holder dispatches; failover from a hard kill of the leader takes ~13 seconds with the tuned 30-second lock TTL + 30-second non-leader poll. Schedule survives restart since it lives in Redis. No application changes — the existing app.conf.beat_schedule dict is ingested by RedBeat on first boot
  • Full audit attribution — every audit row records who drove the change, not just what happened. Admin endpoints record the credential (token:<name> / admin:session:<user>:<role> / admin:legacy_key); portal mutations record the Entra-resolved user (portal:user:<email>) or portal:anonymous when SSO is disabled; signed-token approvals record api:approval_token (approver:<email>). The same attribution flows into the order, asset, asset-type, approval, and delegation audit rows so any change can be traced back to the specific credential that triggered it
  • Field-level data classification — tag each asset attribute as internal, pii, phi, or pci; the portal renders matching warning badges next to sensitive fields when requesters fill them in, and the classification flows into the audit-log snapshot for downstream retention queries

Finance & Chargeback

  • Cost / chargeback per asset definition — set monthly_cost, currency, and cost_center on each definition; the Cost Report page aggregates active orders into projected monthly spend per cost center with CSV export
  • AD-driven consumer breakdown — at order creation we snapshot the requester's AD attributes (department, cost_center, company, employeeID, title; attribute names configurable in Settings) onto each order, so the Cost Report can also slice spend by consuming team / department, and the per-order CSV carries every requester's full HR identity for spreadsheet pivots. Snapshot runs on every creation path — portal, public POST /orders/, and the ServiceNow webhook — so externally-driven orders feed the same consumer-side rows
  • Per-order cost projection — the portal's order detail page renders the projected total (monthly_cost × months_requested) in the Access & Duration card whenever the asset definition is priced; users see what their request will cost before / after approval
  • Cost-threshold alerts — set monthly spend ceilings per (cost_center, currency) on the Cost Report page; a daily Beat task at 04:00 emails the configured recipients (and posts a Teams card when teams.mode=enabled) on breach. Hysteresis via cost.threshold_alert_quiet_hours (default 24h) suppresses repeats; edits to a threshold clear the alert clock so the next breach re-alerts immediately. Provider totals cards on the report flag breaches in red so the dashboard reads at a glance
  • Historical view — daily Beat task at 02:00 captures all three cost-report views into cost_report_snapshots. The Cost Report page gets an As of date picker that reads from the snapshot table for past dates (falls back to live data when no snapshot exists). Retention configurable via cost.snapshot_retention_days (default 365)
  • FX conversion — admins set a canonical reporting currency (cost.fx.canonical, default EUR) and a static rate map (cost.fx.rates); the Cost Report page gets a Show in currency selector that converts mixed-currency totals via cross-rates so summary cards collapse to a single figure per cost center. Currencies without configured rates surface in a meta banner

Admin UI

  • Dashboard with live pool status tiles (auto-refreshing HTMX fragments)
  • Setup checklist on the dashboard — auto-derived from current DB state, separates "essential" from "recommended", each pending item links to the relevant config page; collapses once everything is done and stays out of the way until something changes
  • Pool capacity warnings on the dashboard — pools at ≥80% fill (warning, amber) or ≥95% (critical, red) surface in a banner above the status tiles, listed by severity with one-click links to the affected asset definition or pool view
  • Full asset type configuration (categories, attributes, automation strategy, approvals)
  • Runbook management with drag-and-drop step ordering (mouse via the handle on each row, plus ↑ / ↓ buttons for keyboard accessibility)
  • Email template editor with variable placeholders (per-action templates)
  • Central settings for AD, SMTP, vSphere, XenServer, SCCM, Entra ID
  • Configurable app branding (title, logo, logo position/size)
  • Global variables available to runbooks and scripts
  • Audit log viewer and order change log
  • Asset pool management with bulk import
  • Session-based login (plus X-Admin-Key header for API access)

Integrations

  • Active Directory / LDAP -- user validation, manager lookup, group membership
  • OpenID Connect IdP -- portal SSO via any compliant provider (Entra ID, Okta, Ping, Google, Keycloak, …)
  • vSphere / XenServer / XCP-ng -- VM lifecycle operations via PowerShell
  • SCCM -- task sequence triggers for OS deployment
  • SMTP -- transactional email notifications
  • ServiceNow -- inbound webhook for order dispatch

Architecture

                    +------------------+
                    |   Nginx (SSL)    |
                    +--------+---------+
                             |
                    +--------+---------+
                    |   FastAPI (API)  |
                    |   Admin UI       |
                    |   Portal         |
                    +----+--------+----+
                         |        |
                +--------+--+  +--+--------+
                | PostgreSQL |  |   Redis   |
                +------------+  +-----+-----+
                                      |
                         +------------+------------+
                         |            |            |
                    +----+----+ +----+----+ +-----+-----+
                    |  Worker | |  Beat   | |  Flower   |
                    | (Celery)| |(Sched.) | | (Monitor) |
                    +----+----+ +---------+ +-----------+
                         |
              +----------+----------+
              |          |          |
          +---+---+ +---+---+ +---+---+
          |vSphere| | SCCM  | |  AD   |
          +-------+ +-------+ +-------+

Stack

Layer Technology
API / Dispatcher FastAPI (Python 3.12)
Workflow Engine Celery + Redis
Scheduling Celery Beat
Database PostgreSQL 16 (SQLAlchemy + Alembic)
Frontend HTMX + Jinja2 + Tailwind CSS
Portal Authentication OIDC SSO — any compliant IdP (Entra ID, Okta, …) + on-prem LDAP
VM Operations PowerShell / PowerCLI
Directory Services Active Directory (msldap)
Deployment Docker Compose

Quick Start (Local)

git clone https://github.com/XenPool/ipsolis.git
cd ipsolis

cp .env.example .env
# Edit .env -- set database credentials and API secrets

# Build and start the full stack in the background
docker compose up -d --build

# Apply database migrations (required on first install AND after every upgrade)
docker compose exec api alembic upgrade head

The api service does not auto-run migrations at startup, so this step is required on first install. The same command is also how you upgrade the schema after pulling new code.

Service URL
Self-Service Portal http://localhost:8000/portal
Admin UI http://localhost:8000/ui/
API Docs (Swagger) http://localhost:8000/docs
Celery Flower http://localhost:5555

On first visit to /ui/, the admin login renders a "Create first administrator" form (RBAC first-run setup). Create the initial superadmin, then configure external systems (Active Directory, SMTP, vSphere, Entra ID SSO) through the Admin UI at /ui/settings. The dashboard's setup checklist tracks what's left to configure.

Two run modes

The repository ships two compose files. The main one is the full stack (postgres / redis / api / worker / beat / flower); the second is a small overlay (just nginx) that adds TLS termination in front of the api.

Mode Command When
Direct docker compose up -d Dev. API on http://localhost:8000/, no proxy.
TLS-fronted docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d Pre-live / prod. Nginx handles TLS using nginx/ssl/cert.pem + nginx/ssl/key.pem; reach the app at https://<your-host>/.

The overlay is purely additive — same database, same migrations, same image tags. Switch between modes by stopping (down) and starting with the alternate command.

Production Deployment

See the full deployment guide: docs/DEPLOYMENT.md

High-availability deployment patterns (multi-replica api / worker, Postgres standby + failover) live in section 12 of docs/DEPLOYMENT.md. Grafana dashboard + Prometheus alerts in docs/grafana/; ops runbooks in docs/runbooks/.

Summary:

  1. Provision a Linux server with Docker
  2. Configure .env with secure credentials
  3. Set up SSL certificates (internal CA, mkcert, or Let's Encrypt)
  4. Start with docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d
  5. Run migrations: docker compose exec -T api alembic upgrade head
  6. Configure AD, SMTP, and Entra ID through the Admin UI

Project Structure

api/
  app/
    models/         SQLAlchemy ORM models
    routes/         FastAPI routers (admin, admin_auth, admin_modules,
                    admin_runbooks, admin_standalone_runbooks,
                    admin_maintenance, admin_users, admin_self,
                    admin_api_tokens, admin_license, admin_setup,
                    admin_seed_export, admin_cost_report,
                    admin_approval_delegations, approvals_external,
                    portal, portal_delegations, auth, orders,
                    metrics, ui)
    schemas/        Pydantic request/response schemas
    templates/      Jinja2 templates (Admin UI + Portal + admin login)
    static/         Static JS/CSS assets served by FastAPI
    utils/          AD (msldap), capacity, MSAL, admin auth, PS param parser,
                    RBAC, password (PBKDF2), api_tokens, secrets resolver
                    (Vault / CCP), approval token signer + decision helper,
                    SoD detection, classification, metrics, tracing, audit
  alembic/
    versions/       Database migrations (0001 ... 0093, head bumps with each
                    feature slice — see `docker compose exec api alembic
                    history` for the full chain)
worker/
  tasks/
    modules/        Atomic workflow modules (pool_manager, vsphere,
                    active_directory, notifications, target_executor,
                    teams_notify, maintenance, config_reader, secrets,
                    audit_helper, step_helper, registry)
    workflows/      Orchestration (dynamic_runner, standalone_runner,
                    ps_module_installer, license_check,
                    audit_retention, api_token_purge,
                    approval_reminders, approval_auto_decline,
                    cost_threshold_alerter, cost_report_snapshot,
                    update_checker)
    tracing.py      OpenTelemetry setup for the worker side
scripts/
  modules/          Per-category PowerShell script modules synced from the DB
                    (ad / sccm / sql / test / vmware / xenserver) — seed
                    material only, runtime reads from the DB
  runbooks/         Standalone runbook JSON snapshots (seed material)
tools/
  validate_locales.py  Portal i18n JSON key-tree validator
locales/            Portal i18n (de/en/es/fr/it JSON)
nginx/              Reverse-proxy + TLS config (production overlay)
backups/            Persisted DB dumps (bind-mounted into api + worker)
licenses/           Signed `.lic` license file (read-write)
docs/
  DEPLOYMENT.md             Production deployment guide
  grafana/                  Ready-to-import dashboard + Prometheus alerts
  runbooks/                 Operational runbooks (e.g. compose project rename)

Data Privacy

This software is designed for on-premises deployment. All data stays within your infrastructure.

What personal data is stored

Data Where Purpose
Email address, display name orders, order_approvals Order processing, notifications
sAMAccountName orders (RDP/admin user lists) Access provisioning
Manager relationship Queried live from AD, not stored Approval workflow
Action history audit_log Accountability and compliance
Session token Browser cookie (xp_session) Authentication

Built-in safeguards

  • No data leaves your network (zero telemetry, no cloud dependencies)
  • Tamper-evident audit log (BEFORE-statement triggers block DELETE / UPDATE / TRUNCATE outside a documented bypass)
  • Per-classification audit retention windows (PII / PHI / PCI configurable independently of the global window)
  • Five-tier admin RBAC with per-asset-type ACL grants and separation-of-duties enforcement
  • OIDC SSO for the portal — any compliant IdP (no password storage on the portal side)
  • Admin password storage uses PBKDF2-SHA256 (600k iterations, OWASP-2023)
  • External secret management (HashiCorp Vault / CyberArk CCP / Azure Key Vault / AWS Secrets Manager / CyberArk Conjur) replaces plaintext credentials in app_config; bulk-migration tool to push existing plaintext to the chosen backend in one pass
  • All traffic encrypted via HTTPS (nginx TLS termination)
  • Field-level data classification badges so requesters know which fields are sensitive before submitting

Planned enhancements

  • Order-history retention with automatic cleanup
  • User data export (data portability)
  • User data anonymization/deletion
  • Configurable session cookie hardening (production defaults)
  • Privacy notice integration for the portal

Operators are responsible for maintaining their own records of processing activities and providing appropriate privacy notices to their users as required by applicable regulations.

Screenshots

Coming soon

Roadmap

Shipped

  • Multi-language support (i18n) — portal available in DE / EN / ES / FR / IT
  • Dashboard with live pool status tiles, setup checklist, pool capacity warnings
  • Maintenance UI (backups, health probes, queue inspection)
  • PowerShell module management (Gallery + manual upload, with Linux compatibility flag)
  • Standalone runbooks (ad-hoc + cron-scheduled)
  • Per-classification audit-log retention with tamper-evident triggers
  • Role-based admin access — five-tier ladder with per-asset-type ACL grants and SoD enforcement
  • API token management for external integrations (per-token scopes + role binding)
  • Audit log viewer + SIEM streaming (Splunk HEC / Microsoft Sentinel / generic webhook)
  • OpenTelemetry tracing (api + Celery worker) + Prometheus metrics + Grafana dashboard
  • External secret management (HashiCorp Vault + CyberArk CCP/AIM + Azure Key Vault + AWS Secrets Manager + CyberArk Conjur)
  • HA Beat scheduler (celery-redbeat with Redis-backed distributed lock)
  • Cost / chargeback per asset definition with provider + consumer (AD-driven) views
  • Approval reminders, escalation, delegation (admin + portal self-service), and auto-decline

Open

  • Access certification campaigns — slice 1 + slice 2 (admin CRUD + kickoff + manager portal page + signed-token review URLs + email reminders / overdue / escalation + auto-revoke on overdue)
  • HR feed + SCIM 2.0 — slice 1 (unified leaver flow, HR webhook with Workday/SAP/MS-Graph adapters, SCIM 2.0 leaver subset)
  • HR feed + SCIM — slice 2 (full SCIM filter grammar, /Groups shim, bulk operations)
  • Cost report: threshold alerting (per-cost_center/currency monthly limits with email + optional Teams-card alerts and hysteresis)
  • Cost report: historical view via daily snapshot table + ?as_of= query
  • Cost report: FX conversion across mixed-currency cost centers via configurable rate map
  • Data retention and automatic cleanup (order history)
  • User data export and deletion (GDPR-style data portability)
  • Optional Sentry integration for error tracking
  • Terraform provider for asset definition configuration

License

ip·Solis is source-available under the XenPool Commercial Source License v1.0 — see the Licensing section above for the summary (free productive use up to 25 active users, plus private and 30-day evaluation use; production use with more than 25 active users requires a purchased volume-band license).

See LICENSE for the full license text. Get a commercial license at the ip·Solis license shop.

This project bundles third-party open-source components under their own licenses (MIT, BSD, Apache-2.0, LGPL, and others). See THIRD-PARTY-LICENSES.md for the complete list.

Contributing

Contributions are welcome! Please open an issue first to discuss what you'd like to change.

Support


Built by XenPool GmbH -- born from 30 years of datacenter operations.

About

Self-hosted IT asset lifecycle management — self-service portal, approval workflows and PowerShell runbook automation for VDIs, app access and any IT asset.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors