Compare commits
No commits in common. "main" and "v0.2.2" have entirely different histories.
@ -1,82 +0,0 @@
|
|||||||
# mcvsphere OAuth Configuration Template
|
|
||||||
# Copy to .env and configure for your environment
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# cp .env.oauth.example .env
|
|
||||||
# # Edit .env with your values
|
|
||||||
# docker compose -f docker-compose.oauth-standalone.yml up -d
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Docker Compose
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
COMPOSE_PROJECT_NAME=mcvsphere
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# vCenter Connection (Required)
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
VCENTER_HOST=vcenter.example.com
|
|
||||||
VCENTER_USER=mcpservice@vsphere.local
|
|
||||||
VCENTER_PASSWORD=your-secure-password
|
|
||||||
|
|
||||||
# Optional: Skip SSL verification (dev only - use false in production)
|
|
||||||
VCENTER_INSECURE=false
|
|
||||||
|
|
||||||
# Optional: Specify defaults (auto-detected if not set)
|
|
||||||
# VCENTER_DATACENTER=Datacenter
|
|
||||||
# VCENTER_CLUSTER=Cluster
|
|
||||||
# VCENTER_DATASTORE=datastore1
|
|
||||||
# VCENTER_NETWORK=VM Network
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# MCP Transport (Required for OAuth)
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
MCP_TRANSPORT=streamable-http
|
|
||||||
MCP_HOST=0.0.0.0
|
|
||||||
MCP_PORT=8080
|
|
||||||
|
|
||||||
# Your public domain (must match Caddy proxy)
|
|
||||||
MCP_DOMAIN=mcp.example.com
|
|
||||||
|
|
||||||
# TLS mode: 'internal' for self-signed (dev), remove for auto HTTPS (prod)
|
|
||||||
MCP_TLS_MODE=internal
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# OAuth / OIDC Provider (Required)
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
OAUTH_ENABLED=true
|
|
||||||
|
|
||||||
# OIDC Discovery URL (ends with /.well-known/openid-configuration)
|
|
||||||
# Examples:
|
|
||||||
# Authentik: https://auth.example.com/application/o/mcvsphere/
|
|
||||||
# Keycloak: https://keycloak.example.com/realms/myrealm
|
|
||||||
# Auth0: https://myapp.auth0.com/
|
|
||||||
# Okta: https://myorg.okta.com/oauth2/default
|
|
||||||
OAUTH_ISSUER_URL=https://auth.example.com/application/o/mcvsphere/
|
|
||||||
|
|
||||||
# OAuth Client Credentials (from your OIDC provider)
|
|
||||||
OAUTH_CLIENT_ID=your-client-id
|
|
||||||
OAUTH_CLIENT_SECRET=your-client-secret
|
|
||||||
|
|
||||||
# Public callback URL (must be accessible from browser)
|
|
||||||
OAUTH_BASE_URL=https://mcp.example.com
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# RBAC Permission Groups
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Create these groups in your OIDC provider and assign users:
|
|
||||||
#
|
|
||||||
# | Group | Access Level |
|
|
||||||
# |------------------------|---------------------------------|
|
|
||||||
# | vsphere-super-admins | Full control (all 94 tools) |
|
|
||||||
# | vsphere-host-admins | Host operations + VM management |
|
|
||||||
# | vsphere-admins | VM lifecycle management |
|
|
||||||
# | vsphere-operators | Power ops + snapshots |
|
|
||||||
# | vsphere-readers | Read-only |
|
|
||||||
#
|
|
||||||
# Users without any vsphere-* group will be denied access (default-deny).
|
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Optional Settings
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# LOG_LEVEL=INFO
|
|
||||||
# MCVSPHERE_VERSION=0.2.2
|
|
||||||
14
Dockerfile
14
Dockerfile
@ -48,11 +48,8 @@ ENV PATH="/app/.venv/bin:$PATH"
|
|||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENV PYTHONDONTWRITEBYTECODE=1
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
|
||||||
# Default transport - override with MCP_TRANSPORT env var
|
# Default to SSE transport for Docker
|
||||||
# stdio: Direct CLI usage (default for local)
|
ENV MCP_TRANSPORT=sse
|
||||||
# sse: Server-Sent Events (legacy HTTP)
|
|
||||||
# streamable-http: HTTP with OAuth support (required for multi-user)
|
|
||||||
ENV MCP_TRANSPORT=streamable-http
|
|
||||||
ENV MCP_HOST=0.0.0.0
|
ENV MCP_HOST=0.0.0.0
|
||||||
ENV MCP_PORT=8080
|
ENV MCP_PORT=8080
|
||||||
|
|
||||||
@ -61,9 +58,10 @@ USER mcpuser
|
|||||||
|
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
# Health check - works with both SSE and streamable-http
|
# Health check
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/.well-known/oauth-authorization-server')" || exit 1
|
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080')" || exit 1
|
||||||
|
|
||||||
# Run the MCP server - transport configured via environment
|
# Run the MCP server
|
||||||
ENTRYPOINT ["mcvsphere"]
|
ENTRYPOINT ["mcvsphere"]
|
||||||
|
CMD ["--transport", "sse"]
|
||||||
|
|||||||
@ -235,89 +235,15 @@ MCP_LOG_LEVEL=DEBUG
|
|||||||
log_level: "DEBUG"
|
log_level: "DEBUG"
|
||||||
```
|
```
|
||||||
|
|
||||||
## OAuth Multi-User Mode
|
|
||||||
|
|
||||||
For shared infrastructure or production deployments, mcvsphere supports OAuth 2.1 with any OIDC provider. This enables:
|
|
||||||
|
|
||||||
- **Browser-based authentication** via Authentik, Keycloak, Auth0, Okta, etc.
|
|
||||||
- **Group-based RBAC** with 5 permission levels
|
|
||||||
- **Audit logging** with user identity
|
|
||||||
|
|
||||||
### Quick Start (Existing OIDC Provider)
|
|
||||||
|
|
||||||
If you already have an OIDC provider:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Copy and configure environment
|
|
||||||
cp .env.oauth.example .env
|
|
||||||
# Edit .env with your OIDC provider details
|
|
||||||
|
|
||||||
# 2. Start mcvsphere with OAuth
|
|
||||||
docker compose -f docker-compose.oauth-standalone.yml up -d
|
|
||||||
|
|
||||||
# 3. Add to Claude Code
|
|
||||||
claude mcp add -t http vsphere https://mcp.example.com/mcp
|
|
||||||
```
|
|
||||||
|
|
||||||
### Quick Start (New Authentik Deployment)
|
|
||||||
|
|
||||||
To deploy mcvsphere with a complete Authentik identity provider:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Generate secrets and configure
|
|
||||||
./scripts/setup-oauth.sh
|
|
||||||
|
|
||||||
# 2. Start full stack (mcvsphere + Authentik + PostgreSQL + Redis)
|
|
||||||
docker compose -f docker-compose.oauth.yml up -d
|
|
||||||
|
|
||||||
# 3. Configure Authentik at https://auth.yourdomain.com
|
|
||||||
# - Create OAuth2 provider
|
|
||||||
# - Create vsphere-* groups
|
|
||||||
# - Assign users to groups
|
|
||||||
```
|
|
||||||
|
|
||||||
### RBAC Permission Groups
|
|
||||||
|
|
||||||
Create these groups in your OIDC provider:
|
|
||||||
|
|
||||||
| Group | Access Level |
|
|
||||||
|-------|--------------|
|
|
||||||
| `vsphere-super-admins` | Full control (all 94 tools) |
|
|
||||||
| `vsphere-host-admins` | Host operations + VM management |
|
|
||||||
| `vsphere-admins` | VM lifecycle management |
|
|
||||||
| `vsphere-operators` | Power ops + snapshots |
|
|
||||||
| `vsphere-readers` | Read-only |
|
|
||||||
|
|
||||||
Users without any `vsphere-*` group are denied access (default-deny security).
|
|
||||||
|
|
||||||
### Required Environment Variables
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Transport (must be streamable-http for OAuth)
|
|
||||||
MCP_TRANSPORT=streamable-http
|
|
||||||
|
|
||||||
# OIDC Provider
|
|
||||||
OAUTH_ENABLED=true
|
|
||||||
OAUTH_ISSUER_URL=https://auth.example.com/application/o/mcvsphere/
|
|
||||||
OAUTH_CLIENT_ID=your-client-id
|
|
||||||
OAUTH_CLIENT_SECRET=your-client-secret
|
|
||||||
OAUTH_BASE_URL=https://mcp.example.com
|
|
||||||
```
|
|
||||||
|
|
||||||
See [OAUTH-ARCHITECTURE.md](OAUTH-ARCHITECTURE.md) for detailed setup and troubleshooting.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Production Deployment
|
## Production Deployment
|
||||||
|
|
||||||
### Security Recommendations
|
### Security Recommendations
|
||||||
|
|
||||||
1. Use a dedicated service account for vCenter access
|
1. Use a dedicated user account for vCenter access
|
||||||
2. Enable OAuth authentication (not API keys)
|
2. Enable API key authentication
|
||||||
3. Use valid SSL certificates (set `VCENTER_INSECURE=false`)
|
3. Use valid SSL certificates (set `insecure: false`)
|
||||||
4. Limit container resources
|
4. Limit container resources
|
||||||
5. Use Docker secrets for sensitive data
|
5. Use Docker secrets for sensitive data
|
||||||
6. Deploy behind a reverse proxy with HTTPS (Caddy recommended)
|
|
||||||
|
|
||||||
### High Availability
|
### High Availability
|
||||||
|
|
||||||
|
|||||||
@ -1,64 +0,0 @@
|
|||||||
# mcvsphere with OAuth - Standalone Mode
|
|
||||||
# For users who already have an OIDC provider (Authentik, Keycloak, Auth0, Okta, etc.)
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# 1. Copy .env.oauth.example to .env
|
|
||||||
# 2. Configure your OIDC provider settings
|
|
||||||
# 3. docker compose -f docker-compose.oauth-standalone.yml up -d
|
|
||||||
#
|
|
||||||
# Requires:
|
|
||||||
# - External OIDC provider with OAuth 2.1 support
|
|
||||||
# - Caddy network (caddy-docker-proxy) for HTTPS termination
|
|
||||||
#
|
|
||||||
# For full Authentik deployment, use docker-compose.oauth.yml instead
|
|
||||||
|
|
||||||
services:
|
|
||||||
mcvsphere:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
image: mcvsphere:${MCVSPHERE_VERSION:-latest}
|
|
||||||
container_name: mcvsphere
|
|
||||||
restart: unless-stopped
|
|
||||||
env_file:
|
|
||||||
- .env
|
|
||||||
environment:
|
|
||||||
# Transport - streamable-http required for OAuth
|
|
||||||
MCP_TRANSPORT: streamable-http
|
|
||||||
MCP_HOST: 0.0.0.0
|
|
||||||
MCP_PORT: 8080
|
|
||||||
# OAuth - set in .env file
|
|
||||||
OAUTH_ENABLED: ${OAUTH_ENABLED:-true}
|
|
||||||
volumes:
|
|
||||||
- ./logs:/app/logs
|
|
||||||
networks:
|
|
||||||
- caddy
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8080/.well-known/oauth-authorization-server')"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 15s
|
|
||||||
labels:
|
|
||||||
# Caddy reverse proxy - configure domain in .env
|
|
||||||
caddy: ${MCP_DOMAIN:-mcp.localhost}
|
|
||||||
caddy.reverse_proxy: "{{upstreams 8080}}"
|
|
||||||
# TLS - use 'internal' for local dev, remove for production (auto HTTPS)
|
|
||||||
caddy.tls: ${MCP_TLS_MODE:-internal}
|
|
||||||
# WebSocket/streaming support
|
|
||||||
caddy.reverse_proxy.flush_interval: "-1"
|
|
||||||
caddy.reverse_proxy.transport: http
|
|
||||||
caddy.reverse_proxy.transport.read_timeout: "0"
|
|
||||||
caddy.reverse_proxy.transport.write_timeout: "0"
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 512M
|
|
||||||
cpus: '1.0'
|
|
||||||
reservations:
|
|
||||||
memory: 256M
|
|
||||||
cpus: '0.25'
|
|
||||||
|
|
||||||
networks:
|
|
||||||
caddy:
|
|
||||||
external: true
|
|
||||||
Loading…
x
Reference in New Issue
Block a user