# Getting Started with Charybdis This guide gets you from zero to a running Charybdis instance: a software catalog with a gRPC API, optional Backstage YAML adapter, and plugin integrations on entity events. ## Prerequisites - **Rust** 1.70+ ([install](https://rustup.rs/)) - **PostgreSQL** 14+ - **protoc** + `libprotobuf-dev` (for the build script) - **grpcurl** for testing (optional, [install](https://github.com/fullstorydev/grpcurl)) ## Install ```bash git clone cd charybdis cargo build --release # Binary at target/release/charybdis-server ``` ## Quick Start ### 1. Start PostgreSQL ```bash docker run -d \ --name charybdis-postgres \ -e POSTGRES_PASSWORD=mysecretpassword \ -p 5432:5432 \ postgres:15 ``` ### 2. Configure ```bash cp config.toml.example config.toml export DATABASE_URL="postgresql://postgres:mysecretpassword@localhost:5432/postgres" ``` `config.toml` reads `${DATABASE_URL}` from the environment. See [Configuration](#configuration) below for all options. ### 3. Run ```bash cargo run ``` Expected startup logs: ``` INFO charybdis: Database ready INFO charybdis: Event bus started successfully INFO charybdis: EntityService server listening on [::1]:50051 ``` ### 4. Verify ```bash grpcurl -plaintext localhost:50051 list # charybdis.entities.EntityService # charybdis.ingestion.IngestionService # grpc.reflection.v1.ServerReflection ``` ## Create Your First Entity ```bash grpcurl -plaintext -d '{ "entity": { "kind": "Component", "component_metadata": { "name": "payment-api", "namespace": "production", "description": "Payment processing service", "tags": ["api", "critical"] }, "component_spec": { "type": "service", "lifecycle": "production", "owner": "team-payments" } } }' localhost:50051 charybdis.entities.EntityService/CreateEntity ``` Response: ```json { "entity": { "id": "550e8400-e29b-41d4-a716-446655440000", "kind": "Component", "componentMetadata": { "...": "..." }, "createdAt": "2026-06-01T10:00:00Z", "updatedAt": "2026-06-01T10:00:00Z" } } ``` ### Retrieve and list ```bash # Get by ID grpcurl -plaintext \ -d '{"id": "550e8400-e29b-41d4-a716-446655440000"}' \ localhost:50051 charybdis.entities.EntityService/GetEntity # List all grpcurl -plaintext -d '{}' \ localhost:50051 charybdis.entities.EntityService/ListEntities # Filter by kind and name grpcurl -plaintext \ -d '{"kind": "Component", "name": "payment-api"}' \ localhost:50051 charybdis.entities.EntityService/ListEntities ``` ## Entity Kinds The valid `kind` values are: `Component`, `System`, `API`, `User`, `Group`, `Domain`, `Resource`, `Finding`. Each kind uses a matching `_metadata` + `_spec` payload. Conceptual reference: [core-concepts.md](core-concepts.md). Per-kind protobuf definitions: `proto/core/*.proto`. ### Component example with metadata and annotations ```bash grpcurl -plaintext -d '{ "entity": { "kind": "Component", "component_metadata": { "name": "payment-service", "namespace": "production", "description": "Payment processing", "labels": { "team": "payments", "tier": "critical" }, "links": [{ "url": "https://dashboard.company.com/payments", "title": "Dashboard", "icon": "dashboard" }], "tags": ["payments", "pci-compliant"] }, "component_spec": { "type": "service", "lifecycle": "production", "owner": "team-payments" }, "annotations": { "github.com/repo-slug": "myorg/payment-service", "pagerduty.com/service-id": "PXYZ123" } } }' localhost:50051 charybdis.entities.EntityService/CreateEntity ``` ## Registering Entities from CI Charybdis is designed to be called from pipelines. With `grpcurl` available in your runner: ```yaml # Example pipeline step (Gitea Actions / GitHub Actions syntax) - name: Register service in Charybdis run: | grpcurl -plaintext \ -d "{ \"entity\": { \"kind\": \"Component\", \"component_metadata\": { \"name\": \"$CI_PROJECT_NAME\", \"namespace\": \"production\" }, \"component_spec\": { \"type\": \"service\", \"lifecycle\": \"production\", \"owner\": \"$CI_PROJECT_NAMESPACE\" }, \"annotations\": { \"repo-slug\": \"$CI_PROJECT_PATH\" } } }" \ charybdis.internal:50051 \ charybdis.entities.EntityService/CreateEntity ``` In production, secure the endpoint with mTLS (see [Enabling Security](#enabling-security)). ## Enabling Security Charybdis ships with mTLS + RBAC disabled for local exploration. For shared or production environments, enable both. ### 1. Generate dev certificates ```bash ./deploy/scripts/generate-dev-certs.sh ``` This writes `deploy/certs/` with: - `ca.pem` — CA - `server-cert.pem` / `server-key.pem` — server - `admin-cert.pem` / `admin-key.pem` — admin client - (and per-role client certs) ### 2. Enable in `config.toml` ```toml [security.mtls] enabled = true server_cert = "./deploy/certs/server-cert.pem" server_key = "./deploy/certs/server-key.pem" client_ca_cert = "./deploy/certs/ca.pem" [security.rbac] enabled = true ``` Restart Charybdis. RBAC defaults map cert OUs to roles (`platform-team` → full access, `automation` → CRUD without delete, `plugins` → read-only). ### 3. Call with mTLS ```bash grpcurl \ -cacert deploy/certs/ca.pem \ -cert deploy/certs/admin-cert.pem \ -key deploy/certs/admin-key.pem \ -d '{}' \ localhost:50051 charybdis.entities.EntityService/ListEntities ``` Full reference (custom role mappings, audit logging, reverse-proxy mode): [security.md](security.md). ## Backstage Migration (Optional) If you currently run Backstage, Charybdis serves entities in Backstage's Location YAML format: ```yaml # backstage app-config.yaml catalog: locations: - type: url target: http://your-charybdis-host:8080/yaml/locations rules: - allow: [Component, System, API, User, Group] ``` Backstage discovers entities by polling the endpoint. Entities created via gRPC are visible on the next poll. The YAML adapter is served by an HTTP listener separate from the gRPC port (default `:8080`). ## Configuration Charybdis loads its config from (in order): 1. `./config.toml` 2. `./charybdis.toml` 3. `/etc/charybdis/config.toml` 4. Environment variables (fallback) ### `config.toml` skeleton ```toml [server] grpc_host = "[::1]" grpc_port = 50051 [server.yaml_adapter] enabled = true host = "0.0.0.0" port = 8080 [database] url = "${DATABASE_URL}" max_connections = 10 connection_timeout_secs = 30 [security.mtls] enabled = false [security.rbac] enabled = false [telemetry] service_name = "charybdis" environment = "development" enable_console = true [plugins.defectdojo] enabled = false # see plugins/README.md for the full plugin reference ``` `${VAR}` and `${VAR:-default}` substitution works in any string value — keep secrets in the environment, not in the file. ### Environment-variable fallback If no config file is found, these env vars are read: | Variable | Default | Description | |---|---|---| | `DATABASE_URL` | (required) | PostgreSQL connection string | | `GRPC_HOST` | `[::1]` | gRPC bind address | | `GRPC_PORT` | `50051` | gRPC port | | `RUST_LOG` | `info` | Logging level filter | | `SECURITY_MTLS_ENABLED` | `false` | Enable mTLS | | `SECURITY_RBAC_ENABLED` | `false` | Enable RBAC | | `OTEL_ENABLE_CONSOLE` | `true` | Console exporter | | `OTEL_SERVICE_NAME` | `charybdis` | Service name for telemetry | See `config.toml.example` for the complete template. ## Troubleshooting ### Port already in use ``` Error: transport error ``` Find and free port 50051: `lsof -ti:50051 | xargs kill`, or set `GRPC_PORT=50052`. ### Database connection failed Verify the URL: `psql "$DATABASE_URL" -c "SELECT 1;"`. ### Permission denied with security enabled ``` Code: PermissionDenied Message: Role 'X' does not have permission 'Y' ``` Inspect your cert subject (OU determines the role) and the `[security.rbac.permissions]` table in `config.toml`. Reference: [security.md](security.md). ## Next Steps - [Core Concepts](core-concepts.md) — entity model, events, annotations - [Architecture](architecture.md) — protobuf schema, storage, event bus - [Plugins](../plugins/README.md) — DefectDojo, Keycloak, writing your own - [Vision & Roadmap](../VISION.md) — where Charybdis is going