Public Access
initial-commit
This commit is contained in:
+297
@@ -0,0 +1,297 @@
|
||||
# Charybdis Demo
|
||||
|
||||
See the full flow in action: register a service via one gRPC call and watch DefectDojo auto-provision a product — no YAML files, no manual steps. Optionally, see how Backstage can consume entities from Charybdis in real-time via the YAML adapter.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker & Docker Compose
|
||||
- 8GB RAM recommended
|
||||
- Ports available: 5432, 8080, 8081, 50051 (and 3000 if using Backstage)
|
||||
|
||||
## Quick Start (5 minutes)
|
||||
|
||||
### 1. Start the demo stack
|
||||
|
||||
```bash
|
||||
./demo.sh
|
||||
```
|
||||
|
||||
This will start:
|
||||
- ✅ Charybdis (gRPC on :50051, YAML adapter on :8081)
|
||||
- ✅ DefectDojo (UI on :8080)
|
||||
- ✅ PostgreSQL instances for each service
|
||||
- ℹ️ Backstage (UI on :3000) — optional, see [Backstage Integration](#optional-backstage-integration) below
|
||||
|
||||
### 2. Create your first service
|
||||
|
||||
Using grpcurl (if installed):
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{
|
||||
"entity": {
|
||||
"kind": "Component",
|
||||
"component_metadata": {
|
||||
"name": "payment-api",
|
||||
"description": "Payment processing service",
|
||||
"labels": {
|
||||
"team": "payments",
|
||||
"env": "production"
|
||||
},
|
||||
"tags": ["api", "critical"]
|
||||
},
|
||||
"component_spec": {
|
||||
"type": "service",
|
||||
"lifecycle": "production",
|
||||
"owner": "team-payments"
|
||||
}
|
||||
}
|
||||
}' localhost:50051 charybdis.entities.EntityService/CreateEntity
|
||||
```
|
||||
|
||||
Or using the included grpcurl container:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml run --rm grpcurl \
|
||||
-plaintext -d '{
|
||||
"entity": {
|
||||
"kind": "Component",
|
||||
"component_metadata": {
|
||||
"name": "payment-api",
|
||||
"description": "Payment processing service"
|
||||
},
|
||||
"component_spec": {
|
||||
"type": "service",
|
||||
"lifecycle": "production",
|
||||
"owner": "team-payments"
|
||||
}
|
||||
}
|
||||
}' charybdis:50051 charybdis.entities.EntityService/CreateEntity
|
||||
```
|
||||
|
||||
### 3. See the magic happen! ✨
|
||||
|
||||
**In DefectDojo** (http://localhost:8080):
|
||||
- Login: `admin` / `admin`
|
||||
- Go to "Products"
|
||||
- You'll see "payment-api" automatically created! 🎉
|
||||
|
||||
**In Charybdis** (via gRPC):
|
||||
- Query the entity back — it now has annotations:
|
||||
- `defectdojo.com/product-id`
|
||||
- `defectdojo.com/engagement-id` (if auto-create enabled)
|
||||
|
||||
**In the YAML adapter** (http://localhost:8081):
|
||||
- Visit `http://localhost:8081/yaml/locations` — entities are served in Backstage-compatible YAML format
|
||||
- Any Backstage instance pointed at this URL will pick up entities automatically
|
||||
|
||||
## What just happened?
|
||||
|
||||
```
|
||||
1. You created a Component entity in Charybdis (gRPC API)
|
||||
2. Charybdis stored it in PostgreSQL
|
||||
3. Event published: EntityCreated(Component)
|
||||
4. DefectDojo plugin received the event
|
||||
5. Plugin created a Product in DefectDojo via API
|
||||
6. Plugin stored the product_id in entity annotations
|
||||
7. Entity is now queryable via gRPC and available via YAML adapter
|
||||
```
|
||||
|
||||
**30 seconds instead of 30 minutes of manual provisioning — no YAML files, no manual tool setup.**
|
||||
|
||||
## Try more operations
|
||||
|
||||
### List all entities
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{}' localhost:50051 \
|
||||
charybdis.entities.EntityService/ListEntities
|
||||
```
|
||||
|
||||
### Get a specific entity
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{"id": "YOUR_ENTITY_ID"}' localhost:50051 \
|
||||
charybdis.entities.EntityService/GetEntity
|
||||
```
|
||||
|
||||
### Update an entity
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{
|
||||
"id": "YOUR_ENTITY_ID",
|
||||
"entity": {
|
||||
"kind": "Component",
|
||||
"component_metadata": {
|
||||
"name": "payment-api",
|
||||
"description": "Updated description"
|
||||
}
|
||||
}
|
||||
}' localhost:50051 charybdis.entities.EntityService/UpdateEntity
|
||||
```
|
||||
|
||||
→ Check DefectDojo: Product description updated automatically!
|
||||
|
||||
### Delete an entity
|
||||
|
||||
```bash
|
||||
grpcurl -plaintext -d '{"id": "YOUR_ENTITY_ID"}' localhost:50051 \
|
||||
charybdis.entities.EntityService/DeleteEntity
|
||||
```
|
||||
|
||||
→ Check DefectDojo: Product deleted automatically!
|
||||
|
||||
## Explore the stack
|
||||
|
||||
### Check Charybdis logs
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml logs -f charybdis
|
||||
```
|
||||
|
||||
You'll see:
|
||||
- Entity CRUD operations
|
||||
- Event dispatching
|
||||
- Plugin execution
|
||||
- DefectDojo API calls
|
||||
|
||||
### Check DefectDojo
|
||||
|
||||
Open http://localhost:8080
|
||||
- Login: `admin` / `admin`
|
||||
- Products: See auto-created products
|
||||
- Engagements: See auto-created CI/CD engagements
|
||||
|
||||
### Check the YAML Adapter
|
||||
|
||||
```bash
|
||||
# List all entity locations (Backstage-compatible format)
|
||||
curl http://localhost:8081/yaml/locations
|
||||
```
|
||||
|
||||
This endpoint serves entities as Backstage-compatible YAML — useful for Backstage integration or any tool that consumes this format.
|
||||
|
||||
### Access databases
|
||||
|
||||
**Charybdis database:**
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml exec postgres-charybdis \
|
||||
psql -U charybdis -d charybdis
|
||||
```
|
||||
|
||||
**Query entities:**
|
||||
```sql
|
||||
SELECT id, kind, annotations FROM entities;
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Services not starting
|
||||
|
||||
Check logs:
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml logs
|
||||
```
|
||||
|
||||
### DefectDojo API token issue
|
||||
|
||||
Manually get a token:
|
||||
1. Open http://localhost:8080
|
||||
2. Login: `admin` / `admin`
|
||||
3. Go to Settings → API Key
|
||||
4. Copy the token
|
||||
5. Update `.env`: `DEFECTDOJO_API_TOKEN=your-token`
|
||||
6. Restart: `docker-compose -f docker-compose.demo.yml restart charybdis`
|
||||
|
||||
### Port conflicts
|
||||
|
||||
If ports are already in use, edit `docker-compose.demo.yml` to change:
|
||||
- `3000:3000` → `3001:3000` (Backstage)
|
||||
- `8080:8080` → `8082:8080` (DefectDojo)
|
||||
- etc.
|
||||
|
||||
## Clean up
|
||||
|
||||
### Stop services
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml down
|
||||
```
|
||||
|
||||
### Remove all data
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml down -v
|
||||
```
|
||||
|
||||
## Optional: Backstage Integration
|
||||
|
||||
If you use Backstage, point it at the Charybdis YAML adapter to replace static `catalog-info.yaml` files:
|
||||
|
||||
```yaml
|
||||
# backstage app-config.yaml
|
||||
catalog:
|
||||
locations:
|
||||
- type: url
|
||||
target: http://charybdis:8081/yaml/locations
|
||||
rules:
|
||||
- allow: [Component, System, Service, API, User, Group]
|
||||
```
|
||||
|
||||
Backstage will discover all entities from Charybdis automatically. See the `docker-compose.demo.yml` file for the commented-out Backstage service if you want to run it as part of the demo stack.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Read the docs**: [Getting Started](../docs/getting-started.md)
|
||||
2. **Understand the architecture**: [Architecture](../docs/architecture.md)
|
||||
3. **Create your own plugin**: [Plugin Guide](../plugins/README.md)
|
||||
|
||||
## Demo Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Client │ (grpcurl / CI/CD)
|
||||
│ (gRPC) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Charybdis │
|
||||
│ ┌─────────────┐ ┌──────────────┐ │
|
||||
│ │ gRPC API │ │ YAML Adapter │ │
|
||||
│ │ :50051 │ │ :8081 │ │
|
||||
│ └──────┬──────┘ └──────┬───────┘ │
|
||||
│ │ │ │
|
||||
│ ┌──────▼────────────────▼───────┐ │
|
||||
│ │ Entity Repository │ │
|
||||
│ │ (PostgreSQL) │ │
|
||||
│ └──────┬────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────▼────────┐ │
|
||||
│ │ Event Bus │ │
|
||||
│ └──────┬────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────▼────────────────┐ │
|
||||
│ │ Plugin Dispatcher │ │
|
||||
│ │ ┌─────────────────┐ │ │
|
||||
│ │ │ DefectDojo │ │ │
|
||||
│ │ │ Plugin │ │ │
|
||||
│ │ └─────────────────┘ │ │
|
||||
│ └───────────────────────┘ │
|
||||
└──────┬──────────────┬───────────────┘
|
||||
│ │
|
||||
▼ ▼ (YAML Adapter)
|
||||
┌──────────────┐ ┌────────────────────┐
|
||||
│ DefectDojo │ │ Backstage / Any │
|
||||
│ :8080 │ │ compatible UI │
|
||||
└──────────────┘ └────────────────────┘
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
- GitHub Issues: [github.com/charybdis-catalog/charybdis/issues](https://github.com/charybdis-catalog/charybdis/issues)
|
||||
- Documentation: [docs/](docs/)
|
||||
- Discord: [Join our community](https://discord.gg/...)
|
||||
|
||||
---
|
||||
|
||||
**🎉 Welcome to automated DevSecOps orchestration with Charybdis!**
|
||||
@@ -0,0 +1,102 @@
|
||||
# Adding Backstage to Charybdis Demo
|
||||
|
||||
Backstage requires a custom build and cannot be run from a pre-built Docker image.
|
||||
|
||||
## Option 1: Use the YAML Adapter Directly
|
||||
|
||||
You can read entities from Charybdis without Backstage:
|
||||
|
||||
```bash
|
||||
# List all entities
|
||||
curl http://localhost:8081/yaml/locations
|
||||
|
||||
# Get specific entity
|
||||
curl http://localhost:8081/yaml/entities/YOUR_ENTITY_ID
|
||||
```
|
||||
|
||||
## Option 2: Build and Run Backstage
|
||||
|
||||
### 1. Create a Backstage App
|
||||
|
||||
```bash
|
||||
# Install Node.js 18+ first
|
||||
npx @backstage/create-app@latest
|
||||
|
||||
# Follow prompts, name it "backstage-app"
|
||||
cd backstage-app
|
||||
```
|
||||
|
||||
### 2. Configure Charybdis Integration
|
||||
|
||||
Edit `app-config.yaml` and add:
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
locations:
|
||||
# Point to Charybdis YAML adapter
|
||||
- type: url
|
||||
target: http://charybdis:8080/yaml/locations
|
||||
rules:
|
||||
- allow: [Component, System, API, Resource, User, Group, Domain]
|
||||
```
|
||||
|
||||
### 3. Build Docker Image
|
||||
|
||||
Create `backstage-app/Dockerfile`:
|
||||
|
||||
```dockerfile
|
||||
FROM node:18-bookworm-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package.json yarn.lock ./
|
||||
COPY packages packages
|
||||
|
||||
# Install dependencies
|
||||
RUN yarn install --frozen-lockfile --production
|
||||
|
||||
# Build
|
||||
RUN yarn tsc
|
||||
RUN yarn build:backend
|
||||
|
||||
# Run
|
||||
EXPOSE 7007
|
||||
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
|
||||
```
|
||||
|
||||
### 4. Update docker-compose.demo.yml
|
||||
|
||||
Uncomment the Backstage section in `docker-compose.demo.yml`.
|
||||
|
||||
### 5. Start
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.demo.yml up -d backstage
|
||||
```
|
||||
|
||||
Access Backstage at http://localhost:3000
|
||||
|
||||
## Option 3: Run Backstage Locally (Recommended for Development)
|
||||
|
||||
```bash
|
||||
# In backstage-app directory
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Update `app-config.local.yaml`:
|
||||
|
||||
```yaml
|
||||
catalog:
|
||||
locations:
|
||||
- type: url
|
||||
target: http://localhost:8081/yaml/locations
|
||||
rules:
|
||||
- allow: [Component, System, API, Resource, User, Group, Domain]
|
||||
```
|
||||
|
||||
Access at http://localhost:3000
|
||||
|
||||
---
|
||||
|
||||
For more info: https://backstage.io/docs/getting-started/
|
||||
@@ -0,0 +1,92 @@
|
||||
app:
|
||||
title: Charybdis Demo
|
||||
baseUrl: http://localhost:3000
|
||||
|
||||
organization:
|
||||
name: Charybdis
|
||||
|
||||
backend:
|
||||
baseUrl: http://localhost:7007
|
||||
listen:
|
||||
port: 7007
|
||||
csp:
|
||||
connect-src: ["'self'", 'http:', 'https:']
|
||||
cors:
|
||||
origin: http://localhost:3000
|
||||
methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
|
||||
credentials: true
|
||||
database:
|
||||
client: pg
|
||||
connection:
|
||||
host: ${POSTGRES_HOST}
|
||||
port: ${POSTGRES_PORT}
|
||||
user: ${POSTGRES_USER}
|
||||
password: ${POSTGRES_PASSWORD}
|
||||
database: backstage
|
||||
|
||||
integrations:
|
||||
github:
|
||||
- host: github.com
|
||||
# Optional: token for private repos
|
||||
# token: ${GITHUB_TOKEN}
|
||||
|
||||
proxy:
|
||||
'/charybdis':
|
||||
target: ${CHARYBDIS_URL}
|
||||
changeOrigin: true
|
||||
|
||||
# Catalog configuration - Point to Charybdis
|
||||
catalog:
|
||||
import:
|
||||
entityFilename: catalog-info.yaml
|
||||
pullRequestBranchName: backstage-integration
|
||||
|
||||
rules:
|
||||
- allow: [Component, System, API, Resource, Location]
|
||||
|
||||
# Charybdis as a location provider
|
||||
locations:
|
||||
# Dynamic location from Charybdis YAML adapter
|
||||
- type: url
|
||||
target: ${CHARYBDIS_URL}/yaml/locations
|
||||
rules:
|
||||
- allow: [Component, System, API, Resource, User, Group, Domain]
|
||||
|
||||
# Processors
|
||||
processors:
|
||||
githubOrg:
|
||||
providers:
|
||||
- target: https://github.com
|
||||
# Optional: token for private orgs
|
||||
# token: ${GITHUB_TOKEN}
|
||||
|
||||
auth:
|
||||
# For demo purposes, we use guest authentication
|
||||
# In production, configure proper authentication
|
||||
providers:
|
||||
guest:
|
||||
dangerouslyAllowOutsideDevelopment: true
|
||||
|
||||
# Scaffolder configuration
|
||||
scaffolder:
|
||||
defaultAuthor:
|
||||
name: Charybdis
|
||||
email: charybdis@example.com
|
||||
|
||||
# TechDocs configuration (optional)
|
||||
techdocs:
|
||||
builder: 'local'
|
||||
generator:
|
||||
runIn: 'local'
|
||||
publisher:
|
||||
type: 'local'
|
||||
|
||||
# Search configuration (optional)
|
||||
search:
|
||||
pg:
|
||||
highlightOptions:
|
||||
useHighlight: true
|
||||
maxWord: 35
|
||||
minWord: 15
|
||||
shortWord: 3
|
||||
highlightAll: false
|
||||
Executable
+222
@@ -0,0 +1,222 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Run from the deploy/ directory
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}"
|
||||
cat << "EOF"
|
||||
______ __ __ ___
|
||||
/ ____// /_ ____ _ _____ __ __ / /_ ____/ (_)____
|
||||
/ / / __ \ / __ `// ___// / / // __ \ / __ // // __ \
|
||||
/ /___ / / / // /_/ // / / /_/ // /_/ // /_/ // // /_/ /
|
||||
\____//_/ /_/ \__,_//_/ \__, //_.___/ \__,_//_/ \____/
|
||||
/____/
|
||||
EOF
|
||||
echo -e "${NC}"
|
||||
|
||||
echo -e "${GREEN}Charybdis Demo${NC}\n"
|
||||
|
||||
# Detect gRPC client
|
||||
GRPC_CMD=""
|
||||
if command -v buf &> /dev/null; then
|
||||
GRPC_CMD="buf"
|
||||
elif command -v grpcurl &> /dev/null; then
|
||||
GRPC_CMD="grpcurl"
|
||||
else
|
||||
echo -e "${RED}Error: Neither 'buf' nor 'grpcurl' found. Install one:${NC}"
|
||||
echo -e " brew install bufbuild/buf/buf"
|
||||
echo -e " brew install grpcurl"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${BLUE}Using gRPC client: ${GRPC_CMD}${NC}\n"
|
||||
|
||||
# Helper function for gRPC calls
|
||||
grpc_call() {
|
||||
local service_method="$1"
|
||||
local data="$2"
|
||||
local host="${3:-localhost:50051}"
|
||||
|
||||
if [ "$GRPC_CMD" = "buf" ]; then
|
||||
buf curl --protocol grpc --http2-prior-knowledge \
|
||||
-d "$data" \
|
||||
"http://${host}/${service_method}" 2>&1
|
||||
else
|
||||
grpcurl -plaintext -d "$data" "$host" "$service_method" 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if Docker is running
|
||||
if ! docker info > /dev/null 2>&1; then
|
||||
echo -e "${RED}Error: Docker is not running. Please start Docker first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Starting services...${NC}\n"
|
||||
|
||||
# Start core services (Charybdis + Postgres only for quick demo)
|
||||
docker compose -f docker-compose.demo.yml up -d postgres-charybdis 2>/dev/null
|
||||
echo -e "${GREEN} Postgres started${NC}"
|
||||
|
||||
# Wait for Postgres
|
||||
for i in {1..15}; do
|
||||
if docker compose -f docker-compose.demo.yml exec -T postgres-charybdis pg_isready -U charybdis > /dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
docker compose -f docker-compose.demo.yml up -d charybdis 2>/dev/null
|
||||
echo -e "${GREEN} Charybdis started${NC}"
|
||||
|
||||
# Wait for Charybdis gRPC
|
||||
echo -e "\n${BLUE}Waiting for Charybdis to be ready...${NC}"
|
||||
for i in {1..30}; do
|
||||
if timeout 2 bash -c "echo > /dev/tcp/localhost/50051" 2>/dev/null; then
|
||||
echo -e "${GREEN} gRPC server ready on :50051${NC}"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 30 ]; then
|
||||
echo -e "${RED} Charybdis failed to start${NC}"
|
||||
docker compose -f docker-compose.demo.yml logs charybdis | tail -10
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
sleep 2 # Allow service to fully initialize
|
||||
|
||||
# --- Demo: Entity Management ---
|
||||
echo -e "\n${BLUE}=== Entity Management ===${NC}\n"
|
||||
|
||||
echo -e "${YELLOW}1. Creating a Component...${NC}"
|
||||
RESULT=$(grpc_call "charybdis.entities.EntityService/CreateEntity" '{
|
||||
"entity": {
|
||||
"kind": "Component",
|
||||
"component_metadata": {
|
||||
"name": "payment-service",
|
||||
"namespace": "default",
|
||||
"description": "Payment processing microservice"
|
||||
},
|
||||
"component_spec": {
|
||||
"type": "service",
|
||||
"lifecycle": "production",
|
||||
"owner": "team-payments"
|
||||
}
|
||||
}
|
||||
}')
|
||||
echo "$RESULT" | head -5
|
||||
ENTITY_ID=$(echo "$RESULT" | grep '"id"' | head -1 | sed 's/.*"id": *"//;s/".*//')
|
||||
echo -e "${GREEN} Created entity: ${ENTITY_ID}${NC}\n"
|
||||
|
||||
echo -e "${YELLOW}2. Listing entities...${NC}"
|
||||
grpc_call "charybdis.entities.EntityService/ListEntities" '{}' | head -5
|
||||
echo -e ""
|
||||
|
||||
# --- Demo: Vulnerability Ingestion ---
|
||||
echo -e "\n${BLUE}=== Vulnerability Ingestion ===${NC}\n"
|
||||
|
||||
# Create a SARIF report
|
||||
SARIF_REPORT=$(cat << 'SARIF'
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"runs": [{
|
||||
"tool": {"driver": {"name": "semgrep", "version": "1.0.0", "rules": [
|
||||
{"id": "sql-injection", "shortDescription": {"text": "SQL Injection"}, "defaultConfiguration": {"level": "error"}, "properties": {"tags": ["CWE-89"]}},
|
||||
{"id": "xss-reflected", "shortDescription": {"text": "Reflected XSS"}, "defaultConfiguration": {"level": "warning"}, "properties": {"tags": ["CWE-79"]}},
|
||||
{"id": "hardcoded-secret", "shortDescription": {"text": "Hardcoded Secret"}, "defaultConfiguration": {"level": "error"}}
|
||||
]}},
|
||||
"results": [
|
||||
{"ruleId": "sql-injection", "level": "error", "message": {"text": "User input in SQL query without parameterization"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/db/queries.rs"}, "region": {"startLine": 42}}}], "partialFingerprints": {"primaryLocationLineHash": "fp-sql-001"}},
|
||||
{"ruleId": "xss-reflected", "level": "warning", "message": {"text": "User input reflected in response without encoding"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/handlers/search.rs"}, "region": {"startLine": 18}}}]},
|
||||
{"ruleId": "hardcoded-secret", "level": "error", "message": {"text": "AWS secret key found in source code"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/config.rs"}, "region": {"startLine": 7}}}]}
|
||||
]
|
||||
}]
|
||||
}
|
||||
SARIF
|
||||
)
|
||||
|
||||
SARIF_B64=$(echo "$SARIF_REPORT" | base64)
|
||||
|
||||
echo -e "${YELLOW}3. Dry-run scan (preview without persisting)...${NC}"
|
||||
grpc_call "charybdis.ingestion.IngestionService/DryRunScan" "{
|
||||
\"component_ref\": \"payment-service\",
|
||||
\"lifecycle\": \"production\",
|
||||
\"format\": \"sarif\",
|
||||
\"data\": \"${SARIF_B64}\"
|
||||
}"
|
||||
echo -e ""
|
||||
|
||||
echo -e "${YELLOW}4. Importing scan (persisting findings)...${NC}"
|
||||
grpc_call "charybdis.ingestion.IngestionService/ImportScan" "{
|
||||
\"component_ref\": \"payment-service\",
|
||||
\"lifecycle\": \"production\",
|
||||
\"format\": \"sarif\",
|
||||
\"data\": \"${SARIF_B64}\"
|
||||
}"
|
||||
echo -e ""
|
||||
|
||||
echo -e "${YELLOW}5. Re-importing same scan (testing deduplication)...${NC}"
|
||||
grpc_call "charybdis.ingestion.IngestionService/ImportScan" "{
|
||||
\"component_ref\": \"payment-service\",
|
||||
\"lifecycle\": \"production\",
|
||||
\"format\": \"sarif\",
|
||||
\"data\": \"${SARIF_B64}\"
|
||||
}"
|
||||
echo -e ""
|
||||
|
||||
# Simulate a fix: remove the SQL injection finding
|
||||
SARIF_FIXED=$(cat << 'SARIF'
|
||||
{
|
||||
"version": "2.1.0",
|
||||
"runs": [{
|
||||
"tool": {"driver": {"name": "semgrep", "version": "1.0.0", "rules": [
|
||||
{"id": "xss-reflected", "shortDescription": {"text": "Reflected XSS"}, "defaultConfiguration": {"level": "warning"}, "properties": {"tags": ["CWE-79"]}},
|
||||
{"id": "hardcoded-secret", "shortDescription": {"text": "Hardcoded Secret"}, "defaultConfiguration": {"level": "error"}}
|
||||
]}},
|
||||
"results": [
|
||||
{"ruleId": "xss-reflected", "level": "warning", "message": {"text": "User input reflected in response without encoding"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/handlers/search.rs"}, "region": {"startLine": 18}}}]},
|
||||
{"ruleId": "hardcoded-secret", "level": "error", "message": {"text": "AWS secret key found in source code"}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/config.rs"}, "region": {"startLine": 7}}}]}
|
||||
]
|
||||
}]
|
||||
}
|
||||
SARIF
|
||||
)
|
||||
|
||||
SARIF_FIXED_B64=$(echo "$SARIF_FIXED" | base64)
|
||||
|
||||
echo -e "${YELLOW}6. Importing scan after fix (SQL injection resolved)...${NC}"
|
||||
grpc_call "charybdis.ingestion.IngestionService/ImportScan" "{
|
||||
\"component_ref\": \"payment-service\",
|
||||
\"lifecycle\": \"production\",
|
||||
\"format\": \"sarif\",
|
||||
\"data\": \"${SARIF_FIXED_B64}\"
|
||||
}"
|
||||
echo -e ""
|
||||
|
||||
# --- Summary ---
|
||||
echo -e "\n${GREEN}=== Demo Complete ===${NC}\n"
|
||||
echo -e "${BLUE}What we demonstrated:${NC}"
|
||||
echo -e " 1. Created a Component entity via gRPC"
|
||||
echo -e " 2. Dry-run scan: preview findings without persisting"
|
||||
echo -e " 3. Import scan: persist 3 findings (SQL injection, XSS, hardcoded secret)"
|
||||
echo -e " 4. Deduplication: re-import same scan -> all unchanged"
|
||||
echo -e " 5. Auto-resolution: import without SQL injection -> marked as resolved"
|
||||
echo ""
|
||||
echo -e "${BLUE}Access:${NC}"
|
||||
echo -e " gRPC: localhost:50051"
|
||||
echo -e " YAML Adapter: http://localhost:8081"
|
||||
echo ""
|
||||
echo -e "${BLUE}Stop:${NC}"
|
||||
echo -e " docker compose -f docker-compose.demo.yml down"
|
||||
echo ""
|
||||
echo -e "${BLUE}Clean up:${NC}"
|
||||
echo -e " docker compose -f docker-compose.demo.yml down -v"
|
||||
echo ""
|
||||
@@ -0,0 +1,233 @@
|
||||
version: '3.8'
|
||||
|
||||
# Demo stack secrets — override via .env file or environment variables.
|
||||
# These are NOT production credentials. Generate your own before deploying.
|
||||
x-dd-secrets: &dd-secrets
|
||||
DD_SECRET_KEY: ${DD_SECRET_KEY:-CHANGE_ME_generate_a_random_secret_key}
|
||||
DD_CREDENTIAL_AES_256_KEY: ${DD_CREDENTIAL_AES_256_KEY:-CHANGE_ME_generate_a_base64_aes_key}
|
||||
|
||||
services:
|
||||
# PostgreSQL for Charybdis
|
||||
postgres-charybdis:
|
||||
image: postgres:15-alpine
|
||||
container_name: charybdis-postgres
|
||||
environment:
|
||||
POSTGRES_DB: charybdis
|
||||
POSTGRES_USER: charybdis
|
||||
POSTGRES_PASSWORD: ${CHARYBDIS_DB_PASSWORD:-charybdis}
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- charybdis-postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U charybdis"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- charybdis-network
|
||||
|
||||
# PostgreSQL for DefectDojo
|
||||
postgres-defectdojo:
|
||||
image: postgres:15-alpine
|
||||
container_name: defectdojo-postgres
|
||||
environment:
|
||||
POSTGRES_DB: defectdojo
|
||||
POSTGRES_USER: defectdojo
|
||||
POSTGRES_PASSWORD: ${DD_DB_PASSWORD:-defectdojo}
|
||||
volumes:
|
||||
- defectdojo-postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U defectdojo"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- charybdis-network
|
||||
|
||||
# Redis for DefectDojo
|
||||
redis-defectdojo:
|
||||
image: redis:7-alpine
|
||||
container_name: defectdojo-redis
|
||||
networks:
|
||||
- charybdis-network
|
||||
|
||||
# DefectDojo
|
||||
defectdojo-uwsgi:
|
||||
image: defectdojo/defectdojo-django:2.38.1
|
||||
platform: linux/amd64 # Force x86_64 emulation for ARM64 (Mac Silicon)
|
||||
container_name: defectdojo-uwsgi
|
||||
depends_on:
|
||||
postgres-defectdojo:
|
||||
condition: service_healthy
|
||||
redis-defectdojo:
|
||||
condition: service_started
|
||||
environment:
|
||||
DD_DEBUG: 'True'
|
||||
DD_ALLOWED_HOSTS: '*'
|
||||
DD_DATABASE_URL: postgresql://defectdojo:${DD_DB_PASSWORD:-defectdojo}@postgres-defectdojo:5432/defectdojo
|
||||
DD_CELERY_BROKER_URL: redis://redis-defectdojo:6379/0
|
||||
<<: *dd-secrets
|
||||
DD_INITIALIZE: 'true'
|
||||
DD_ADMIN_USER: ${DD_ADMIN_USER:-admin}
|
||||
DD_ADMIN_PASSWORD: ${DD_ADMIN_PASSWORD:-admin}
|
||||
DD_ADMIN_MAIL: 'admin@example.com'
|
||||
ports:
|
||||
- "8080:8081" # DefectDojo HTTP endpoint is on 8081 inside container
|
||||
volumes:
|
||||
- defectdojo-media:/app/media
|
||||
networks:
|
||||
- charybdis-network
|
||||
# Healthcheck disabled - DefectDojo takes time to initialize
|
||||
# Access will be available after ~2 minutes
|
||||
# healthcheck:
|
||||
# test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/').read()"]
|
||||
# interval: 30s
|
||||
# timeout: 10s
|
||||
# retries: 5
|
||||
# start_period: 120s
|
||||
|
||||
# DefectDojo Celery Worker
|
||||
defectdojo-celery:
|
||||
image: defectdojo/defectdojo-django:2.38.1
|
||||
platform: linux/amd64 # Force x86_64 emulation for ARM64 (Mac Silicon)
|
||||
container_name: defectdojo-celery
|
||||
depends_on:
|
||||
- defectdojo-uwsgi
|
||||
- redis-defectdojo
|
||||
environment:
|
||||
DD_DATABASE_URL: postgresql://defectdojo:${DD_DB_PASSWORD:-defectdojo}@postgres-defectdojo:5432/defectdojo
|
||||
DD_CELERY_BROKER_URL: redis://redis-defectdojo:6379/0
|
||||
<<: *dd-secrets
|
||||
entrypoint: ['/entrypoint-celery-worker.sh']
|
||||
networks:
|
||||
- charybdis-network
|
||||
|
||||
# DefectDojo Celery Beat
|
||||
defectdojo-beat:
|
||||
image: defectdojo/defectdojo-django:2.38.1
|
||||
platform: linux/amd64 # Force x86_64 emulation for ARM64 (Mac Silicon)
|
||||
container_name: defectdojo-beat
|
||||
depends_on:
|
||||
- defectdojo-celery
|
||||
environment:
|
||||
DD_DATABASE_URL: postgresql://defectdojo:${DD_DB_PASSWORD:-defectdojo}@postgres-defectdojo:5432/defectdojo
|
||||
DD_CELERY_BROKER_URL: redis://redis-defectdojo:6379/0
|
||||
<<: *dd-secrets
|
||||
entrypoint: ['/entrypoint-celery-beat.sh']
|
||||
networks:
|
||||
- charybdis-network
|
||||
|
||||
# Keycloak (Identity Provider)
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:24.0
|
||||
container_name: charybdis-keycloak
|
||||
command: start-dev --import-realm
|
||||
environment:
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin}
|
||||
ports:
|
||||
- "8082:8080"
|
||||
volumes:
|
||||
- ./scripts/keycloak/charybdis-realm.json:/opt/keycloak/data/import/charybdis-realm.json:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/8080 && echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\n\r\n' >&3 && cat <&3 | grep -q '200'"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 15
|
||||
start_period: 30s
|
||||
networks:
|
||||
- charybdis-network
|
||||
|
||||
# Charybdis
|
||||
charybdis:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: Dockerfile
|
||||
container_name: charybdis
|
||||
depends_on:
|
||||
postgres-charybdis:
|
||||
condition: service_healthy
|
||||
keycloak:
|
||||
condition: service_healthy
|
||||
defectdojo-uwsgi:
|
||||
condition: service_started # Changed from service_healthy since healthcheck is disabled
|
||||
environment:
|
||||
DATABASE_URL: postgresql://charybdis:${CHARYBDIS_DB_PASSWORD:-charybdis}@postgres-charybdis:5432/charybdis
|
||||
RUST_LOG: info
|
||||
DEFECTDOJO_API_URL: http://defectdojo-uwsgi:8081
|
||||
DEFECTDOJO_API_TOKEN: ${DEFECTDOJO_API_TOKEN:-changeme}
|
||||
ports:
|
||||
- "50051:50051" # gRPC
|
||||
- "8081:8080" # YAML adapter
|
||||
volumes:
|
||||
- ./config.toml:/app/config.toml:ro
|
||||
networks:
|
||||
- charybdis-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Backstage (commented out - requires custom build)
|
||||
# To enable Backstage:
|
||||
# 1. Follow https://backstage.io/docs/getting-started/create-an-app
|
||||
# 2. Build Docker image: cd backstage-app && yarn install && yarn build
|
||||
# 3. Uncomment this section and postgres-backstage below
|
||||
|
||||
# backstage:
|
||||
# build:
|
||||
# context: ./backstage-app
|
||||
# dockerfile: Dockerfile
|
||||
# container_name: backstage
|
||||
# depends_on:
|
||||
# - charybdis
|
||||
# - postgres-backstage
|
||||
# environment:
|
||||
# POSTGRES_HOST: postgres-backstage
|
||||
# POSTGRES_PORT: 5432
|
||||
# POSTGRES_USER: backstage
|
||||
# POSTGRES_PASSWORD: backstage
|
||||
# CHARYBDIS_URL: http://charybdis:8080
|
||||
# ports:
|
||||
# - "3000:3000"
|
||||
# - "7007:7007"
|
||||
# volumes:
|
||||
# - ./backstage/app-config.yaml:/app/app-config.yaml:ro
|
||||
# networks:
|
||||
# - charybdis-network
|
||||
# restart: unless-stopped
|
||||
|
||||
# postgres-backstage:
|
||||
# image: postgres:15-alpine
|
||||
# container_name: backstage-postgres
|
||||
# environment:
|
||||
# POSTGRES_DB: backstage
|
||||
# POSTGRES_USER: backstage
|
||||
# POSTGRES_PASSWORD: backstage
|
||||
# volumes:
|
||||
# - backstage-postgres-data:/var/lib/postgresql/data
|
||||
# healthcheck:
|
||||
# test: ["CMD-SHELL", "pg_isready -U backstage"]
|
||||
# interval: 10s
|
||||
# timeout: 5s
|
||||
# retries: 5
|
||||
# networks:
|
||||
# - charybdis-network
|
||||
|
||||
# Helper: grpcurl for testing
|
||||
grpcurl:
|
||||
image: fullstorydev/grpcurl:latest
|
||||
container_name: charybdis-grpcurl
|
||||
network_mode: service:charybdis
|
||||
entrypoint: ["/bin/sh"]
|
||||
command: ["-c", "sleep infinity"]
|
||||
profiles:
|
||||
- tools
|
||||
|
||||
volumes:
|
||||
charybdis-postgres-data:
|
||||
defectdojo-postgres-data:
|
||||
defectdojo-media:
|
||||
# backstage-postgres-data: # Uncomment if enabling Backstage
|
||||
|
||||
networks:
|
||||
charybdis-network:
|
||||
driver: bridge
|
||||
@@ -0,0 +1,78 @@
|
||||
# Docker Compose for OpenTelemetry Testing
|
||||
# This sets up a complete observability stack for local development
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# OpenTelemetry Collector
|
||||
# Receives telemetry data and exports to backends
|
||||
otel-collector:
|
||||
image: otel/opentelemetry-collector-contrib:latest
|
||||
container_name: charybdis-otel-collector
|
||||
command: ["--config=/etc/otel-collector-config.yaml"]
|
||||
volumes:
|
||||
- ./docker/otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
ports:
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
- "8888:8888" # Prometheus metrics exposed by the collector
|
||||
- "8889:8889" # Prometheus exporter metrics
|
||||
- "13133:13133" # health_check extension
|
||||
networks:
|
||||
- charybdis-telemetry
|
||||
|
||||
# Jaeger - Distributed Tracing UI
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:latest
|
||||
container_name: charybdis-jaeger
|
||||
environment:
|
||||
- COLLECTOR_OTLP_ENABLED=true
|
||||
ports:
|
||||
- "16686:16686" # Jaeger UI
|
||||
- "14250:14250" # Jaeger gRPC
|
||||
networks:
|
||||
- charybdis-telemetry
|
||||
|
||||
# Prometheus - Metrics Storage
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: charybdis-prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--web.enable-lifecycle'
|
||||
volumes:
|
||||
- ./docker/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus-data:/prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
networks:
|
||||
- charybdis-telemetry
|
||||
|
||||
# Grafana - Visualization
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: charybdis-grafana
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
- GF_SECURITY_ADMIN_USER=admin
|
||||
volumes:
|
||||
- ./docker/grafana/provisioning:/etc/grafana/provisioning
|
||||
- grafana-data:/var/lib/grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
- charybdis-telemetry
|
||||
depends_on:
|
||||
- prometheus
|
||||
- jaeger
|
||||
|
||||
networks:
|
||||
charybdis-telemetry:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
prometheus-data:
|
||||
grafana-data:
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
# scripts/generate-client-cert.sh
|
||||
# Flexible client certificate generation for any use case
|
||||
# Usage: ./scripts/generate-client-cert.sh <name> <ou> [days-valid]
|
||||
|
||||
set -e
|
||||
|
||||
NAME=$1
|
||||
OU=$2
|
||||
DAYS_VALID=${3:-365}
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CERT_DIR="${SCRIPT_DIR}/../certs"
|
||||
|
||||
if [ -z "$NAME" ] || [ -z "$OU" ]; then
|
||||
echo "Usage: $0 <name> <ou> [days-valid]"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 payment-service automation # Service certificate (default 365 days)"
|
||||
echo " $0 jane-doe platform-team # Admin certificate"
|
||||
echo " $0 jira-plugin plugins # Plugin certificate"
|
||||
echo " $0 contractor-bob monitoring 30 # Temporary certificate (30 days)"
|
||||
echo ""
|
||||
echo "Common OU values:"
|
||||
echo " automation → service-writer role (create, read, update, list)"
|
||||
echo " platform-team → admin role (full access)"
|
||||
echo " monitoring → catalog-reader role (read, list only)"
|
||||
echo " plugins → plugin role (read, update annotations)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure cert directory exists
|
||||
mkdir -p "$CERT_DIR"
|
||||
cd "$CERT_DIR"
|
||||
|
||||
# Check if CA exists
|
||||
if [ ! -f "ca.pem" ] || [ ! -f "ca-key.pem" ]; then
|
||||
echo "❌ Error: CA not found!"
|
||||
echo " Run ./scripts/generate-dev-certs.sh first to create the CA"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔐 Generating certificate for: $NAME"
|
||||
echo " OU: $OU"
|
||||
echo " Organization: Company"
|
||||
echo " Valid for: $DAYS_VALID days"
|
||||
echo ""
|
||||
|
||||
# Generate private key
|
||||
openssl genrsa -out "${NAME}-key.pem" 2048 2>/dev/null
|
||||
|
||||
# Generate CSR
|
||||
openssl req -new \
|
||||
-key "${NAME}-key.pem" \
|
||||
-out "${NAME}.csr" \
|
||||
-subj "/CN=${NAME}/OU=${OU}/O=Company/C=US" \
|
||||
2>/dev/null
|
||||
|
||||
# Sign certificate
|
||||
openssl x509 -req \
|
||||
-days ${DAYS_VALID} \
|
||||
-in "${NAME}.csr" \
|
||||
-CA ca.pem \
|
||||
-CAkey ca-key.pem \
|
||||
-CAcreateserial \
|
||||
-out "${NAME}-cert.pem" \
|
||||
-extfile <(echo "extendedKeyUsage=clientAuth") \
|
||||
2>/dev/null
|
||||
|
||||
# Clean up CSR
|
||||
rm "${NAME}.csr"
|
||||
|
||||
echo "✅ Certificate generated successfully!"
|
||||
echo ""
|
||||
echo "📋 Files created:"
|
||||
echo " ${CERT_DIR}/${NAME}-cert.pem"
|
||||
echo " ${CERT_DIR}/${NAME}-key.pem"
|
||||
echo ""
|
||||
echo "🔍 Certificate details:"
|
||||
openssl x509 -in "${NAME}-cert.pem" -noout -subject -dates
|
||||
echo ""
|
||||
echo "🎯 Role mapping (based on OU):"
|
||||
case $OU in
|
||||
"platform-team"|"admin")
|
||||
echo " Role: admin"
|
||||
echo " Permissions: Full access (entity:*)"
|
||||
;;
|
||||
"automation"|"ci-cd")
|
||||
echo " Role: service-writer"
|
||||
echo " Permissions: create, read, update, list entities"
|
||||
;;
|
||||
"platform"|"monitoring"|"dashboard")
|
||||
echo " Role: catalog-reader"
|
||||
echo " Permissions: read, list entities only"
|
||||
;;
|
||||
"plugins")
|
||||
echo " Role: plugin"
|
||||
echo " Permissions: read, update annotations only"
|
||||
;;
|
||||
*)
|
||||
echo " Role: Unknown - check security-config.yaml for mapping"
|
||||
echo " You may need to add a rule for OU=${OU}"
|
||||
;;
|
||||
esac
|
||||
echo ""
|
||||
echo "📦 Distribute these files securely to the user:"
|
||||
echo " ${NAME}-cert.pem"
|
||||
echo " ${NAME}-key.pem"
|
||||
echo " ca.pem"
|
||||
echo ""
|
||||
echo "💡 Example distribution:"
|
||||
echo " # Copy to user's machine:"
|
||||
echo " scp ${NAME}-cert.pem ${NAME}-key.pem ca.pem user@host:~/.charybdis/"
|
||||
echo ""
|
||||
echo " # Or store in secrets manager:"
|
||||
echo " vault kv put secret/charybdis/${NAME} \\"
|
||||
echo " cert=@${NAME}-cert.pem \\"
|
||||
echo " key=@${NAME}-key.pem \\"
|
||||
echo " ca=@ca.pem"
|
||||
echo ""
|
||||
echo "🔒 Security reminder:"
|
||||
echo " - Keep private key (${NAME}-key.pem) secret!"
|
||||
echo " - Store securely (1Password, Vault, etc.)"
|
||||
echo " - Never commit to git"
|
||||
echo " - Valid for ${DAYS_VALID} days (expires $(date -v +${DAYS_VALID}d '+%Y-%m-%d' 2>/dev/null || date -d "+${DAYS_VALID} days" '+%Y-%m-%d' 2>/dev/null || echo 'N/A'))"
|
||||
echo ""
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Charybdis Development Certificate Generation Script
|
||||
# This script generates self-signed certificates for local development and testing
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CERT_DIR="${SCRIPT_DIR}/../certs"
|
||||
DAYS_VALID=365
|
||||
|
||||
echo "🔐 Charybdis Certificate Generation"
|
||||
echo "===================================="
|
||||
echo ""
|
||||
|
||||
# Create certs directory
|
||||
mkdir -p "${CERT_DIR}"
|
||||
cd "${CERT_DIR}"
|
||||
|
||||
# Function to generate certificate
|
||||
generate_cert() {
|
||||
local name=$1
|
||||
local cn=$2
|
||||
local ou=$3
|
||||
local cert_type=$4 # "server" or "client"
|
||||
|
||||
echo "📝 Generating ${name}..."
|
||||
|
||||
# Generate private key
|
||||
openssl genrsa -out "${name}-key.pem" 2048 2>/dev/null
|
||||
|
||||
# Generate CSR
|
||||
openssl req -new \
|
||||
-key "${name}-key.pem" \
|
||||
-out "${name}.csr" \
|
||||
-subj "/CN=${cn}/OU=${ou}/O=Charybdis-Dev/C=US" \
|
||||
2>/dev/null
|
||||
|
||||
# Generate certificate
|
||||
if [ "${cert_type}" = "server" ]; then
|
||||
openssl x509 -req \
|
||||
-days ${DAYS_VALID} \
|
||||
-in "${name}.csr" \
|
||||
-CA ca.pem \
|
||||
-CAkey ca-key.pem \
|
||||
-CAcreateserial \
|
||||
-out "${name}-cert.pem" \
|
||||
-extfile <(echo "extendedKeyUsage=serverAuth
|
||||
subjectAltName=DNS:localhost,DNS:charybdis,DNS:charybdis.local,IP:127.0.0.1") \
|
||||
2>/dev/null
|
||||
else
|
||||
openssl x509 -req \
|
||||
-days ${DAYS_VALID} \
|
||||
-in "${name}.csr" \
|
||||
-CA ca.pem \
|
||||
-CAkey ca-key.pem \
|
||||
-CAcreateserial \
|
||||
-out "${name}-cert.pem" \
|
||||
-extfile <(echo "extendedKeyUsage=clientAuth") \
|
||||
2>/dev/null
|
||||
fi
|
||||
|
||||
# Clean up CSR
|
||||
rm "${name}.csr"
|
||||
|
||||
echo " ✅ Generated ${name}-cert.pem and ${name}-key.pem"
|
||||
}
|
||||
|
||||
# 1. Generate Root CA
|
||||
echo "🏛️ Generating Root CA..."
|
||||
if [ ! -f ca.pem ]; then
|
||||
openssl genrsa -out ca-key.pem 4096 2>/dev/null
|
||||
openssl req -new -x509 \
|
||||
-days 3650 \
|
||||
-key ca-key.pem \
|
||||
-out ca.pem \
|
||||
-subj "/CN=Charybdis Dev Root CA/O=Charybdis-Dev/C=US" \
|
||||
2>/dev/null
|
||||
echo " ✅ Generated ca.pem (Root CA)"
|
||||
else
|
||||
echo " ℹ️ Root CA already exists, skipping"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 2. Generate Server Certificate
|
||||
echo "🖥️ Generating Server Certificate..."
|
||||
generate_cert "server" "localhost" "platform" "server"
|
||||
echo ""
|
||||
|
||||
# 3. Generate Client Certificates
|
||||
echo "👥 Generating Client Certificates..."
|
||||
echo ""
|
||||
|
||||
# Admin client
|
||||
generate_cert "admin" "admin-user" "platform-team" "client"
|
||||
|
||||
# CI/CD Pipeline client
|
||||
generate_cert "ci-pipeline" "ci-pipeline" "automation" "client"
|
||||
|
||||
# Backstage client
|
||||
generate_cert "backstage" "backstage" "platform" "client"
|
||||
|
||||
# DefectDojo plugin client
|
||||
generate_cert "defectdojo-plugin" "defectdojo-plugin" "plugins" "client"
|
||||
|
||||
# DependencyTrack plugin client
|
||||
generate_cert "dependencytrack-plugin" "dependencytrack-plugin" "plugins" "client"
|
||||
|
||||
echo ""
|
||||
echo "✅ Certificate Generation Complete!"
|
||||
echo ""
|
||||
echo "📂 Certificates generated in: ${CERT_DIR}"
|
||||
echo ""
|
||||
echo "📋 Summary:"
|
||||
echo " - Root CA: ca.pem, ca-key.pem"
|
||||
echo " - Server: server-cert.pem, server-key.pem"
|
||||
echo " - Clients:"
|
||||
echo " • admin-cert.pem, admin-key.pem (role: admin)"
|
||||
echo " • ci-pipeline-cert.pem, ci-pipeline-key.pem (role: service-writer)"
|
||||
echo " • backstage-cert.pem, backstage-key.pem (role: catalog-reader)"
|
||||
echo " • defectdojo-plugin-cert.pem, defectdojo-plugin-key.pem (role: plugin)"
|
||||
echo " • dependencytrack-plugin-cert.pem, dependencytrack-plugin-key.pem (role: plugin)"
|
||||
echo ""
|
||||
echo "🔍 Verify certificates:"
|
||||
echo " openssl x509 -in ${CERT_DIR}/server-cert.pem -text -noout"
|
||||
echo ""
|
||||
echo "🚀 Use with Charybdis:"
|
||||
echo " export SECURITY_MTLS_ENABLED=true"
|
||||
echo " export SECURITY_MTLS_SERVER_CERT=${CERT_DIR}/server-cert.pem"
|
||||
echo " export SECURITY_MTLS_SERVER_KEY=${CERT_DIR}/server-key.pem"
|
||||
echo " export SECURITY_MTLS_CLIENT_CA=${CERT_DIR}/ca.pem"
|
||||
echo ""
|
||||
echo "⚠️ These are DEVELOPMENT certificates only!"
|
||||
echo " Do NOT use in production. Generate proper certificates from a trusted CA."
|
||||
echo ""
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"realm": "charybdis",
|
||||
"enabled": true,
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "charybdis-sync",
|
||||
"enabled": true,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "charybdis-sync-secret",
|
||||
"serviceAccountsEnabled": true,
|
||||
"directAccessGrantsEnabled": false,
|
||||
"publicClient": false,
|
||||
"protocol": "openid-connect",
|
||||
"fullScopeAllowed": true
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "engineering",
|
||||
"path": "/engineering",
|
||||
"subGroups": [
|
||||
{
|
||||
"name": "backend",
|
||||
"path": "/engineering/backend",
|
||||
"subGroups": []
|
||||
},
|
||||
{
|
||||
"name": "frontend",
|
||||
"path": "/engineering/frontend",
|
||||
"subGroups": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "security",
|
||||
"path": "/security",
|
||||
"subGroups": []
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "alice",
|
||||
"email": "alice@example.com",
|
||||
"firstName": "Alice",
|
||||
"lastName": "Martin",
|
||||
"enabled": true,
|
||||
"emailVerified": true,
|
||||
"groups": ["/engineering/backend", "/security"]
|
||||
},
|
||||
{
|
||||
"username": "bob",
|
||||
"email": "bob@example.com",
|
||||
"firstName": "Bob",
|
||||
"lastName": "Dupont",
|
||||
"enabled": true,
|
||||
"emailVerified": true,
|
||||
"groups": ["/engineering/frontend"]
|
||||
},
|
||||
{
|
||||
"username": "charlie",
|
||||
"email": "charlie@example.com",
|
||||
"firstName": "Charlie",
|
||||
"lastName": "Garcia",
|
||||
"enabled": true,
|
||||
"emailVerified": false,
|
||||
"groups": ["/engineering"]
|
||||
},
|
||||
{
|
||||
"username": "service-account-charybdis-sync",
|
||||
"enabled": true,
|
||||
"serviceAccountClientId": "charybdis-sync",
|
||||
"clientRoles": {
|
||||
"realm-management": [
|
||||
"view-users",
|
||||
"query-users",
|
||||
"query-groups",
|
||||
"view-realm"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user