Skip to content

Repository files navigation

Infrastructure Management API

A production-oriented, security-focused backend for infrastructure automation.

Overview

This application exposes typed infrastructure actions via FastAPI, with all endpoints dynamically generated from YAML configuration. Commands are executed safely through Make targets using asyncio.subprocessnever shell=True.

Architecture

Angular Frontend
    ->
FastAPI Backend
    ->
Infrastructure Execution Layer
    ->
Shell Commands / Make / Ansible / Docker / Helm / VirtualBox (future)

Key Design Decisions

  • YAML-Driven API: All endpoints, request models, and OpenAPI documentation are generated from configs/infrastructure.yaml. Adding a new infrastructure action requires only a YAML change and a Makefile target.
  • Safe Execution: All commands are executed via asyncio.create_subprocess_exec with argument arrays. No shell string concatenation.
  • Strong Typing: Pydantic v2 models with Literal enums enforce allowed values at the API layer.
  • Audit Foundation: Every execution is logged with structured JSON, actor, arguments, and result.
  • Auth-Ready: User, Role, and Permission models exist; endpoints accept a current_user dependency that can be swapped for JWT/OAuth2 later.
  • Async Job Tracking: Long-running commands return a job_id immediately; results are queried via GET /api/v1/jobs/{job_id}.

Project Structure

app/
    main.py                    # FastAPI app, middleware, exception handlers
    core/
        config.py              # Pydantic-settings configuration
        logging.py             # Structured JSON logging with request correlation
        security.py            # Input validation and safe execution helpers
        dependencies.py        # FastAPI dependency providers
    api/
        dynamic_routes.py      # YAML-driven route generation (core)
        health.py              # Liveness / readiness probes
        jobs.py                # Async job status endpoint
    domain/
        models/
            command.py         # CommandDefinition, ExecutionResult
            job.py             # Job, JobStatus
    infrastructure/
        command_registry.py    # YAML loader, validator, command index
        command_executor.py    # (future) orchestration layer
        process_runner.py      # Safe asyncio subprocess wrapper
        runner_factory.py      # Extensible runner factory (MakeRunner, future runners)
    schemas/
        common.py              # APIResponse envelope, HealthStatus
    audit/
        logger.py              # Structured audit logging
    auth/
        models.py              # User, Role, Permission enums
        dependencies.py        # current_user stub, permission dependency factory
        permissions.py         # Permission mapping helpers
    jobs/
        manager.py             # In-memory job manager with abstraction layer
configs/
    infrastructure.yaml        # Source of truth for API endpoints
    Makefile                   # Make targets executed by MakeRunner
tests/
    unit/
        test_process_runner.py
        test_command_registry.py
    integration/
        test_api.py

Quick Start

Local Development

# 1. Install dependencies
pip install -r requirements.txt

# 2. Run the server
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# 3. Open Swagger UI
open http://localhost:8000/docs

Docker

# Build and run
docker-compose up --build

# Or build image only
docker build -t infrastructure-api .
docker run -p 8000:8000 infrastructure-api

Configuration

Configuration is loaded from environment variables and .env files via pydantic-settings.

Variable Default Description
APP_NAME infrastructure-api Application name
ENVIRONMENT development Runtime environment
LOG_LEVEL INFO Logging level
COMMAND_TIMEOUT 300 Default command timeout (seconds)
ALLOWED_ORIGINS http://localhost:4200 CORS origins
CONFIG_PATH configs/infrastructure.yaml Infrastructure YAML path
MAKEFILE_PATH configs/Makefile Makefile path

Create a .env file:

cp .env.example .env

YAML Configuration

The configs/infrastructure.yaml defines the entire API surface.

VM_Control:
  PowerControl:
    start_vm:
      type: POST
      args:
        vm_name:
          - vm1
          - vm2
          - vm3
      make: start-vm
      description: Start a virtual machine by name
      async_execution: false

This generates:

  • OpenAPI tag: VM Control
  • Path: POST /api/v1/vm-control/power-control/start-vm
  • Request body: { "vm_name": "vm1" } (enum documented in Swagger)
  • Execution: make -f configs/Makefile start-vm vm_name=vm1

YAML Schema

Field Required Description
type Yes HTTP method (GET, POST, PUT, DELETE)
args Yes Map of argument names to allowed value lists
make Yes Make target to execute
runner No Runner type (make only for now)
timeout No Override command timeout
description No Endpoint description
async_execution No Return job_id immediately if true
audit_enabled No Enable audit logging

Example API Requests

Start a VM

curl -X POST http://localhost:8000/api/v1/vm-control/power-control/start-vm \
  -H "Content-Type: application/json" \
  -d '{"vm_name": "vm1"}'

Stop a VM

curl -X POST http://localhost:8000/api/v1/vm-control/power-control/stop-vm \
  -H "Content-Type: application/json" \
  -d '{"vm_name": "vm2"}'

Docker Compose Up (Async)

curl -X POST http://localhost:8000/api/v1/docker-control/container-lifecycle/compose-up \
  -H "Content-Type: application/json" \
  -d '{"project": "webapp"}'

Returns:

{
  "success": true,
  "data": {
    "job_id": "a1b2c3d4...",
    "status": "pending"
  },
  "error": null,
  "request_id": "..."
}

Check Job Status

curl http://localhost:8000/api/v1/jobs/a1b2c3d4...

Health Checks

curl http://localhost:8000/api/v1/health/live
curl http://localhost:8000/api/v1/health/ready

Security

  • No shell=True: All commands use asyncio.create_subprocess_exec with argument arrays.
  • Argument Allowlists: Every request argument is validated against YAML-defined allowed values.
  • Safe Identifiers: Argument names and values are validated with restrictive regex patterns before subprocess execution.
  • No Arbitrary Execution: The API exposes only pre-defined infrastructure actions; there is no generic command execution endpoint.
  • Audit Logging: Every command execution is logged with actor, arguments, result, and request ID.

Future Extensibility

The architecture supports the following without rewriting API generation:

Feature How
JWT / OAuth2 Replace _resolve_current_user in app/auth/dependencies.py
RBAC Use require_permission() dependency on routes; permissions already mapped per command
SSH Runner Implement SSHRunner(BaseRunner) and register with RunnerFactory.register(RunnerTypeEnum.SSH, SSHRunner)
Kubernetes Add kubernetes runner type and K8sRunner
Scheduled Jobs Extend JobManager with APScheduler or Celery backend
WebSocket Logs Stream ProcessRunner stdout/stderr over WebSocket
Audit Persistence Replace log_audit_event with database/SIEM writer
Multi-user Add database-backed user store; User model is ready

Testing

# Run all tests
pytest

# Run with coverage
pytest --cov=app --cov-report=term-missing

License

MIT

About

Python FastAPI service for control host

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages