Skip to content

About

Internal Developer Platform (IDP) featuring an isolated, zero-registration instant sandbox engine powered by FastAPI, SQLAlchemy, and self-hosted GitHub Actions runner

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Internal Developer Platform API

Python FastAPI Kubernetes Terraform License

A self-service cloud infrastructure and application deployment platform that empowers developers to provision resources and deploy applications without deep DevOps expertise.


Table of Contents


Overview

The Internal Developer Platform (IDP) API is an AWS-first FastAPI platform for provisioning Amazon EKS infrastructure and deploying applications to Kubernetes. AWS is the only supported cloud provider today; additional providers can be added after the AWS workflow is proven.

Live Deployment

The hosted demo runs on an Ubuntu VM through a Cloudflare Quick Tunnel. The URL remains available while the idp-cloudflare service is running, but Cloudflare may assign a new hostname after the service or VM restarts.

Use Cases

  • Self-service deployments: Developers deploy Docker images without managing Kubernetes manifests
  • Infrastructure automation: Provision AWS resources (EKS, networking, databases) via API
  • Multi-tenant environments: Secure namespace isolation and RBAC
  • Real-time monitoring: Track deployment status, logs, and cluster health
  • GitOps-ready: Easily integrated with CI/CD pipelines and ArgoCD

Quick Start

Get the IDP API running locally in 5 minutes:

# 1. Clone the repository
git clone https://github.com/dhamsey3/internal-developer-platform-api.git
cd internal-developer-platform-api

# 2. Create environment file (dry-run mode for local development)
cp .env.example .env

# 3. Install dependencies and run
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload

# If venv creation fails on Debian/Ubuntu:
# sudo apt install python3-venv

# 4. Open the dashboard
open http://127.0.0.1:8000/dashboard/

# 5. Explore API docs
open http://127.0.0.1:8000/docs

Running tests locally

To run the unit tests locally in an isolated virtual environment, follow these steps:

# create a virtual environment (Debian/Ubuntu: install python3-venv if this fails)
python3 -m venv .venv

# activate and install test dependencies
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt

# run the test suite
python -m pytest -q

If python3 -m venv fails with an error about ensurepip or similar, install the OS package first on Debian/Ubuntu:

sudo apt update && sudo apt install python3-venv

If you cannot use sudo on your machine, the repository includes a GitHub Actions workflow that runs the same test matrix on push and pull requests.

Prerequisites

  • Python 3.9 or later with venv support
  • Docker (for containerized deployments)
  • Kubernetes 1.24+ (optional, for local development use dry-run mode)
  • Terraform 1.0+ (optional, for infrastructure provisioning)
  • PostgreSQL or SQLite (SQLite for local development)

On Debian/Ubuntu, install python3-venv if python3 -m venv is unavailable.


Features

Core Capabilities

  • Authentication & Authorization

    • JWT-based authentication
    • Role-based access control (RBAC)
    • Rate limiting for API protection
  • Kubernetes Deployment Automation

    • One-click application deployments
    • Auto-scaling configuration (HPA)
    • Namespace isolation
    • Service exposure via Ingress
    • Real-time pod logs and status
  • Cloud Infrastructure Provisioning

    • AWS infrastructure via Terraform
    • EKS cluster provisioning
    • Async job queue for long-running tasks
    • State management with encrypted S3 state and native lock files
  • Developer Dashboard

    • Web UI for non-technical users
    • Template-based deployments
    • Real-time status tracking
    • Log viewing and metrics access
  • Observability

    • Prometheus metrics
    • Grafana dashboards
    • Cluster health monitoring
    • Pod log aggregation

Architecture

The platform is a developer hub that connects applications, dependencies, deployment destinations, and operational systems. GitHub remains the source and pipeline system; Docker, Kubernetes, and cloud providers remain runtime sources of truth. The IDP stores ownership, desired configuration, readiness, and deployment history.

Core Model

Application
├── Source: repository or container image
├── Resources: database, cache, storage, queue, secrets
├── Destination: local, existing server, cloud, or Kubernetes
├── Deployments: version and runtime status
└── Operations: health, logs, metrics, and rollback

The dashboard guides developers through source, dependencies, destination, and review. Provider details such as IAM roles, Terraform state, kubeconfigs, and networking remain operator concerns.

Destination Readiness

Destinations are registered before developers use them. Each destination adapter reports explicit readiness checks and missing setup:

  • linux_docker: enabled server, dedicated runner label, and application deployment workflow
  • local_docker: local platform agent
  • aws_ecs: AWS account connected through GitHub OIDC
  • existing_kubernetes: scoped Kubernetes deployment identity
  • Azure and Google Cloud adapters can be added behind the same contract

The initial home-vm, local-docker, and aws-sandbox destinations are catalog entries. They remain setup_required until their actual application delivery prerequisites are configured. The platform never marks an application as deployed merely because its metadata was registered.

Request Flow for Application Deployment

  1. User authenticates with JWT
  2. API validates Docker image, namespace, port, replica, ingress, and autoscaling inputs
  3. A deployment row is created in the database
  4. Kubernetes service layer creates namespace, Deployment, Service, Ingress, and HPA
  5. Deployment status, URL, autoscaling settings, and errors are persisted
  6. Users query deployment status, logs, metrics, and cluster health through API endpoints

The existing /deployments Kubernetes API remains available as a compatibility path and is displayed under Operations. New provider-neutral application records use /applications; configured execution adapters will create deployment records in later phases.

Home VM Application Delivery

The home-vm destination deploys container-image applications through the dedicated idp-vm self-hosted runner. The public API does not mount the host Docker socket. A deployment request starts the dedicated GitHub Actions workflow, and the runner reports deploying, running, or failed through an authenticated callback.

One-time operator setup:

  1. Create a fine-grained GitHub token limited to this repository with Actions: write for application workflow dispatch and Contents: read/write for sandbox repository dispatch.
  2. Generate a separate callback token, for example openssl rand -hex 32.
  3. Add the fine-grained token as the GitHub Actions secret IDP_GITHUB_DISPATCH_TOKEN.
  4. Add the callback value as the separate GitHub Actions secret DEPLOYMENT_CALLBACK_TOKEN.
  5. Leave the existing multiline APP_ENV secret unchanged. The deployment pipeline appends both dedicated secrets to the container environment file without replacing APP_ENV.
  6. Add repository variable IDP_API_URL with the stable IDP API origin.
  7. Optionally add APPLICATION_BIND_ADDRESS and APPLICATION_BASE_URL for a network address that can reach application host ports. The bind address defaults to 127.0.0.1; do not use 0.0.0.0 without an intentional firewall policy.

After the next IDP deployment, home-vm becomes ready. Container applications can then be deployed or redeployed from their catalog card.

The runner workflow:

  • validates every dispatch field before using it in Docker commands
  • binds application ports to VM loopback by default
  • checks the application root URL before declaring success
  • restores the previous image when the new image fails its health check
  • keeps one persistent Docker volume per requested PostgreSQL database
  • generates PostgreSQL credentials on the VM and stores them in a 0600 environment file
  • injects DATABASE_URL into the application without sending the password through the API or GitHub payload

The VM-managed environment file is an initial single-server secret adapter, not a replacement for a managed secrets service. AWS deployments should use AWS Secrets Manager or an equivalent external secret provider.


AWS First Deployment

The first supported infrastructure target is Amazon EKS. A real provisioning request creates a VPC, public and private subnets across at least two Availability Zones, NAT egress for private worker nodes, an EKS control plane, and a managed node group. Terraform state is stored in a versioned, encrypted S3 bucket using native S3 lock files.

Keep TERRAFORM_DRY_RUN=true in the IDP application. AWS infrastructure is executed by the AWS Infrastructure GitHub Actions workflow so permanent AWS credentials are not stored on the VM.

One-time AWS and GitHub setup

  1. Use a dedicated AWS sandbox account and configure an AWS Budget with email alerts.
  2. Create a private S3 state bucket with versioning, server-side encryption, and public access blocked.
  3. Add the GitHub OIDC provider token.actions.githubusercontent.com to AWS IAM.
  4. Create a plan role with read-only infrastructure permissions plus access to the S3 state and lock objects. Its trust policy must allow only repo:dhamsey3/internal-developer-platform-api:ref:refs/heads/main.
  5. Create a separate apply role with the permissions needed to manage the declared VPC, EKS, EC2, and prefixed IAM resources. Its trust policy must allow only repo:dhamsey3/internal-developer-platform-api:environment:aws-sandbox. Both roles must require the audience sts.amazonaws.com.
  6. In the GitHub repository, create these Actions variables: AWS_REGION, TF_STATE_BUCKET, AWS_PLAN_ROLE_ARN, and AWS_APPLY_ROLE_ARN.
  7. Create the GitHub environment aws-sandbox, add required reviewers, prevent administrators from bypassing approval, and limit deployment branches to main.

Do not add AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY to GitHub, .env, or the VM. GitHub exchanges its OIDC token for temporary role credentials on each job.

First sandbox run

  1. Open Actions > AWS Infrastructure > Run workflow.
  2. Select plan, use cluster name idp-sandbox, and enter the public egress IP that will access the EKS API followed by /32.
  3. Review the plan summary and estimated AWS resources.
  4. Run it again with apply.
  5. Review the new plan, then approve the waiting aws-sandbox environment deployment.
  6. Validate the cluster, then use the destroy action when the sandbox is no longer needed.

The sandbox defaults to one t3.medium worker, scales to at most two, and uses one NAT gateway. EKS control-plane, EC2, NAT gateway, IPv4, storage, and data-transfer charges can still apply. AWS Budgets provide alerts, not a hard spending limit.

This phase provisions and destroys AWS infrastructure only. Application delivery to EKS remains disabled until the pipeline has a narrowly scoped Kubernetes deployment identity; the VM does not receive AWS credentials or an administrator kubeconfig.


Project Structure

app/              FastAPI app, configuration, logging
api/              Route handlers and Pydantic schemas
auth/             JWT, RBAC, rate limiting
database/         SQLAlchemy models and session lifecycle
services/         Kubernetes, Terraform, deployment, monitoring logic
web/              Developer dashboard served by FastAPI
kubernetes/       Cluster RBAC and network policy examples
terraform/        AWS Terraform templates
helm/             Helm chart for the API itself
monitoring/       Prometheus and Grafana examples
scripts/          Bootstrap and production checklist helpers
tests/            Unit tests

API Endpoints

Authentication

  • POST /auth/register - Register a new user
  • POST /auth/login - Authenticate and receive JWT token
  • GET /auth/me - Get current user info

Infrastructure

  • POST /infrastructure/create - Provision AWS infrastructure
  • GET /infrastructure/{id} - Check infrastructure status
  • DELETE /infrastructure/{id} - Destroy infrastructure

Deployments

  • POST /deployments - Deploy an application
  • GET /deployments/{id} - Get deployment details
  • DELETE /deployments/{id} - Delete a deployment

Kubernetes Operations

  • POST /kubernetes/namespace/create - Create a namespace
  • POST /kubernetes/service/expose - Expose a service
  • POST /kubernetes/autoscaling/create - Configure auto-scaling
  • POST /kubernetes/ingress/create - Create ingress rules

Monitoring

  • GET /monitoring/cluster/health - Get cluster health status
  • GET /monitoring/metrics - Prometheus metrics endpoint
  • GET /monitoring/logs/{pod}?namespace=default - Retrieve pod logs

Documentation

  • GET /docs - Swagger/OpenAPI interactive documentation
  • GET /dashboard/ - Developer-friendly web dashboard

Local Development

Setup Environment

# Copy environment template
cp .env.example .env

For local development without a Kubernetes cluster or Terraform credentials, configure:

KUBERNETES_DRY_RUN=true
TERRAFORM_DRY_RUN=true
DATABASE_URL=sqlite:///./idp.db
ENABLE_PUBLIC_REGISTRATION=true

Install & Run

python3 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate
pip install -r requirements.txt
uvicorn app.main:app --reload

Access the Dashboard

Open your browser and navigate to:

http://127.0.0.1:8000/dashboard/

The dashboard allows you to:

  • Register and log in
  • Deploy Docker images
  • View deployment status
  • Delete deployments
  • Fetch pod logs
  • Select from app templates and image catalogs

Example API Calls

Register a user:

curl -X POST http://localhost:8000/auth/register \
  -H "Content-Type: application/json" \
  -d '{"username":"platform-user","password":"change-me-123"}'

Login and get token:

TOKEN=$(curl -s -X POST http://localhost:8000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"platform-user","password":"change-me-123"}' | jq -r .access_token)

Deploy an application:

curl -X POST http://localhost:8000/deployments \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "demo-api",
    "image": "nginx:1.25",
    "port": 80,
    "replicas": 2,
    "min_replicas": 1,
    "max_replicas": 5,
    "cpu_threshold": 70
  }'

Terraform

The infrastructure API records requests, returns 202 Accepted, and queues Terraform work for a worker that updates the infrastructure status. Local development can use the in-process background job.

Production Setup

  • Use the GitHub OIDC workflow described above for sandbox AWS execution.
  • Keep the API Terraform executor in dry-run mode.
  • Store state in an encrypted, versioned S3 bucket with public access blocked.
  • Use a least-privilege IAM role with a permissions boundary and narrowly scoped iam:PassRole.
  • Require a protected GitHub environment approval before apply or destroy.
  • Use separate AWS accounts, state buckets, roles, and GitHub environments for sandbox and production.
  • Add policy checks, cost estimation, and a durable job/event integration before allowing the IDP UI to trigger this workflow.

Example Infrastructure Request

curl -X POST http://localhost:8000/infrastructure/create \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "platform-dev",
    "cloud_provider": "aws",
    "config": {
      "aws_region": "us-east-1",
      "public_access_cidrs": ["203.0.113.10/32"],
      "single_nat_gateway": true
    }
  }'

Poll for status:

curl -X GET http://localhost:8000/infrastructure/{id} \
  -H "Authorization: Bearer $TOKEN"

Helm Deployment

Render the Helm Chart

helm template idp-api helm/charts/idp-api \
  --set secrets.databaseUrl='postgresql://user:pass@postgres:5432/idp' \
  --set secrets.secretKey='replace-with-long-random-secret'

Install or Upgrade

helm upgrade --install idp-api helm/charts/idp-api \
  --set image.repository=registry.example.com/idp-api \
  --set image.tag=v1 \
  --set secrets.databaseUrl='postgresql://user:pass@postgres:5432/idp' \
  --set secrets.secretKey='replace-with-long-random-secret'

Note: The chart intentionally fails if image.tag is empty. Always use a release tag or digest, never latest.


Security

Implemented

  • JWT authentication with token validation
  • Role-aware user model and RBAC
  • Protected infrastructure, deployment, Kubernetes, and monitoring APIs
  • Redis-backed rate limiting with local fallback
  • Non-root Docker container
  • Security headers and restricted CORS origin configuration
  • Production startup validation for weak/default SECRET_KEY
  • Helm defaults: public registration disabled, debug disabled, read-only root filesystem, dropped Linux capabilities
  • Kubernetes RBAC and network-policy examples
  • No hardcoded production secret requirement in Helm

Create or Reset an Administrator

Public registration should remain disabled in production. Create or reset an administrator from the Ubuntu VM:

docker exec -it idp-api python -m app.admin create --username admin

Recommended for Production

  • Use AWS Secrets Manager, External Secrets Operator, or sealed-secrets
  • Keep public registration disabled unless you implement an invite/admin onboarding flow
  • Replace SQLite with managed PostgreSQL
  • Use Alembic for database migrations
  • Run Terraform through Redis worker queue, Terraform Cloud, Atlantis, GitHub Actions, or Argo Workflows with audit history
  • Enforce tenant-aware namespace ownership
  • Add admission policies with Kyverno or OPA Gatekeeper
  • Use image allowlists and vulnerability scanning
  • Require immutable image digests for production deployments

Observability

The API exposes Prometheus metrics at /monitoring/metrics. Example scrape configuration and Grafana dashboard starters live in the monitoring/ directory.

Recommended Production Stack

  • Prometheus Operator
  • Grafana dashboards for API latency, error rate, Kubernetes deployment state, and Terraform failures
  • Loki or OpenSearch for structured logs
  • Alertmanager alerts for failed provisions, high error rate, and unhealthy clusters

CI/CD

The GitHub Actions workflow installs dependencies, runs linting and tests, builds the Docker image, and deploys the API to the Ubuntu self-hosted runner. The VM deployment uses a persistent Docker volume for SQLite data and verifies /healthz after each release.


Implementation Phases

  • Phase 1: Architecture and folder structure with layered app layout
  • Phase 2: FastAPI backend with auth, validation, database models, OpenAPI, health checks, and rate limiting
  • Phase 3: Kubernetes integration for namespaces, deployments, services, ingress, HPA, status, logs, and safe deletes
  • Phase 4: Terraform automation for AWS templates with apply/destroy and remote-state configuration
  • Phase 5: Monitoring with Prometheus metrics, cluster health, pod logs, and dashboard examples
  • Phase 6: CI/CD with linting, testing, and Docker image build
  • Phase 7: Production hardening (see scripts/prod_checklist.md)

Scaling Recommendations

  • Move long-running deploy/provision tasks to Celery, RQ, Temporal, or Argo Workflows
  • Add per-tenant quotas for namespaces, replicas, CPU, memory, and load balancers
  • Use GitOps with ArgoCD for reconciliation and auditability
  • Split API, worker, scheduler, and webhook receiver into separate deployments
  • Use PostgreSQL with row-level ownership checks and explicit tenant IDs
  • Add blue/green and canary deployment strategies with Argo Rollouts or Flagger

Troubleshooting

Issue: "Kubernetes connection failed" in dry-run mode

Solution: Ensure KUBERNETES_DRY_RUN=true is set in your .env file for local development.

Issue: Dashboard not loading

Solution: Make sure the FastAPI server is running and accessible at http://127.0.0.1:8000. Check firewall settings.

Issue: Deployment fails with authentication error

Solution: Verify your JWT token is valid by calling GET /auth/me with your token.

Issue: Terraform state lock error

Solution: Confirm no other Terraform run is active. If a stale .tflock object remains after a failed run, inspect the active workflows and lock metadata before removing it from the S3 state bucket.


Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -m 'Add your feature')
  4. Push to the branch (git push origin feature/your-feature)
  5. Open a Pull Request

Please ensure:

  • Code follows PEP 8 standards
  • Tests pass (pytest)
  • Documentation is updated
  • Security best practices are followed

License

This project is licensed under the MIT License. See the LICENSE file for details.


Support

For issues, questions, or feedback:


Built with ❤️ for DevOps and Cloud Engineers

About

Internal Developer Platform (IDP) featuring an isolated, zero-registration instant sandbox engine powered by FastAPI, SQLAlchemy, and self-hosted GitHub Actions runner

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages