Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ This project is a **reference implementation** designed to teach and demonstrate
- **Complete stack**: From threat model to production-ready CI/CD
- **Realistic scenario**: Aviation telemetry context with regulatory constraints
- **Documented decisions**: Every security control is explained with rationale
- **Testable**: 300+ tests demonstrating security behaviors
- **Testable**: 470+ tests demonstrating security behaviors
- **Runnable**: Full Docker Compose stack for hands-on learning

---
Expand All @@ -51,6 +51,7 @@ This aviation context justifies strict security requirements:
| Requirement | Justification |
|-------------|---------------|
| **Strong Authentication** | Only authorized aircraft can transmit data |
| **Role-Based Access Control** | 5 roles with least-privilege permissions |
| **Data Integrity** | Telemetry must be tamper-proof (idempotency, checksums) |
| **Privacy Protection** | GPS coordinates rounded, PII minimized in logs |
| **Audit Trail** | All security events logged for compliance |
Expand All @@ -65,6 +66,7 @@ This aviation context justifies strict security requirements:
**SkyLink** is a demonstration platform for connected aircraft services, built with security as a foundational principle. This project showcases practical Security by Design implementations:

- **Multi-layer authentication** (JWT RS256 + mTLS)
- **Role-Based Access Control** (5 roles, 7 permissions, principle of least privilege)
- **Defense in depth** (rate limiting, payload limits, strict validation)
- **Privacy by Design** (PII minimization, structured logging without sensitive data)
- **Secure CI/CD pipeline** (SAST, SCA, DAST, SBOM, image signing)
Expand Down Expand Up @@ -109,15 +111,16 @@ This aviation context justifies strict security requirements:

## Security by Design Features

### 1. Multi-Layer Authentication
### 1. Multi-Layer Authentication & Authorization

| Layer | Mechanism | Implementation |
|-------|-----------|----------------|
| **Transport** | mTLS (Mutual TLS) | X.509 client certificates, CA validation |
| **Application** | JWT RS256 | 2048-bit RSA keys, 15-min expiry, audience validation |
| **Cross-Validation** | CN ↔ JWT sub | Certificate CN must match JWT subject |
| **Authorization** | RBAC | 5 roles, 7 permissions, principle of least privilege |

**Implementation**: [skylink/auth.py](skylink/auth.py), [skylink/mtls.py](skylink/mtls.py)
**Implementation**: [skylink/auth.py](skylink/auth.py), [skylink/mtls.py](skylink/mtls.py), [skylink/rbac.py](skylink/rbac.py)

### 2. Defense in Depth

Expand Down Expand Up @@ -204,7 +207,7 @@ CI/CD pipeline with security gates at every stage:
| **Ruff** | Python linting | lint |
| **Black** | Code formatting | lint |
| **Bandit** | SAST (security linting) | lint |
| **pytest** | Unit tests (305 tests, 81% coverage) | test |
| **pytest** | Unit tests (470+ tests, 81% coverage) | test |
| **Trivy** | Container vulnerability scanning | scan |
| **pip-audit** | Python dependency SCA | scan |
| **Gitleaks** | Secret detection | scan |
Expand Down Expand Up @@ -311,9 +314,9 @@ curl -s -X POST http://localhost:8000/telemetry/ingest \
| `GET` | `/health` | Health check | No |
| `GET` | `/metrics` | Prometheus metrics | No |
| `POST` | `/auth/token` | Obtain JWT token | No |
| `POST` | `/telemetry/ingest` | Ingest telemetry data | JWT |
| `GET` | `/weather/current` | Current weather | JWT |
| `GET` | `/contacts/` | List contacts | JWT |
| `POST` | `/telemetry/ingest` | Ingest telemetry data | JWT + RBAC (telemetry:write) |
| `GET` | `/weather/current` | Current weather | JWT + RBAC (weather:read) |
| `GET` | `/contacts/` | List contacts | JWT + RBAC (contacts:read) |

### HTTP Status Codes

Expand All @@ -323,7 +326,7 @@ curl -s -X POST http://localhost:8000/telemetry/ingest \
| `201` | Created |
| `400` | Validation error |
| `401` | Unauthorized (missing/invalid JWT) |
| `403` | Forbidden (mTLS CN ≠ JWT sub) |
| `403` | Forbidden (mTLS CN ≠ JWT sub, or RBAC permission denied) |
| `409` | Conflict (idempotency violation) |
| `413` | Payload too large |
| `429` | Rate limit exceeded |
Expand All @@ -341,15 +344,20 @@ skylink/
│ ├── mtls.py # mTLS configuration
│ ├── middlewares.py # Security headers, logging, payload limit
│ ├── rate_limit.py # Rate limiting (slowapi)
│ ├── rbac.py # Role-Based Access Control
│ ├── rbac_roles.py # Role and permission definitions
│ ├── config.py # Configuration management
│ └── routers/ # API endpoints
├── telemetry/ # Telemetry service (port 8001)
├── weather/ # Weather service (port 8002)
├── contacts/ # Contacts service (port 8003)
├── scripts/ # PKI & utility scripts
├── tests/ # Test suite
├── kubernetes/ # Kubernetes Helm chart
│ └── skylink/ # Helm chart with security policies
├── docs/ # Documentation
│ ├── DEMO.md # Demo guide
│ ├── KUBERNETES.md # Kubernetes deployment guide
│ ├── TECHNICAL_DOCUMENTATION.md # Technical documentation
│ ├── GITHUB_CI_SETUP.md # GitHub Actions setup guide
│ └── GITLAB_CI_SETUP.md # GitLab CI/CD setup guide
Expand All @@ -370,6 +378,8 @@ skylink/
| [docs/MONITORING.md](docs/MONITORING.md) | Security monitoring with Prometheus and Grafana |
| [docs/KEY_MANAGEMENT.md](docs/KEY_MANAGEMENT.md) | Cryptographic key management, rotation procedures, compliance |
| [docs/AUDIT_LOGGING.md](docs/AUDIT_LOGGING.md) | Audit event logging, security event tracking, compliance |
| [docs/AUTHORIZATION.md](docs/AUTHORIZATION.md) | Role-Based Access Control (RBAC), permissions, role matrix |
| [docs/KUBERNETES.md](docs/KUBERNETES.md) | Kubernetes deployment with Helm, security policies, operations |
| [docs/DEMO.md](docs/DEMO.md) | Step-by-step demonstration walkthrough |
| [docs/TECHNICAL_DOCUMENTATION.md](docs/TECHNICAL_DOCUMENTATION.md) | Complete technical documentation (architecture, security, RRA) |
| [docs/GITHUB_CI_SETUP.md](docs/GITHUB_CI_SETUP.md) | GitHub Actions CI/CD setup guide (secrets, variables, workflow) |
Expand Down Expand Up @@ -404,7 +414,7 @@ make test
poetry run pytest
```

**305 tests** with **81% coverage** — covering authentication, rate limiting, input validation, idempotency, security headers, error handling, and service integration.
**470+ tests** with **81% coverage** — covering authentication, RBAC authorization, rate limiting, input validation, idempotency, OWASP Top 10 security tests, security headers, error handling, and service integration.

---

Expand All @@ -413,8 +423,10 @@ poetry run pytest
- [x] **Threat Modeling** — STRIDE analysis in [docs/THREAT_MODEL.md](docs/THREAT_MODEL.md)
- [x] **Strict Input Validation** — Pydantic `extra="forbid"`, reject unknown fields
- [x] **JWT RS256 Authentication** — Short TTL (15 min), audience validation
- [x] **RBAC Authorization** — 5 roles, 7 permissions, least privilege principle
- [x] **mTLS Cross-Validation** — Certificate CN must match JWT subject
- [x] **Rate Limiting** — Per-identity throttling with Prometheus counter
- [x] **OWASP Top 10 Security Tests** — 97 tests covering injection, XSS, access control, etc.
- [x] **Security Headers** — OWASP recommended set
- [x] **Structured Logging** — JSON format, no PII, trace_id correlation
- [x] **SAST** — Bandit security linting
Expand All @@ -438,7 +450,7 @@ This project aims for a **9+/10 Security by Design** rating. Current status:
| **Threat Modeling** | Complete | STRIDE analysis, 30+ threats identified |
| **Security Architecture** | Complete | DFD, trust boundaries, control mapping |
| **Authentication** | Complete | JWT RS256 + mTLS cross-validation |
| **Authorization** | Partial | Per-identity rate limiting (RBAC planned) |
| **Authorization** | Complete | RBAC with 5 roles, 7 permissions, least privilege |
| **Monitoring & Alerting** | Complete | Prometheus + Grafana + 14 alert rules |
| **Audit Logging** | Complete | 20 event types, JSON format, no PII |
| **Key Management** | Complete | Rotation scripts, compliance docs |
Expand Down
10 changes: 10 additions & 0 deletions docs/AUDIT_LOGGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ curl -s -X POST http://localhost:8000/auth/token \
| `MTLS_FAILURE` | warning | mTLS certificate invalid |
| `MTLS_CN_MISMATCH` | warning | Certificate CN != JWT subject |

### Authorization Events (RBAC)

| Event Type | Severity | Description |
|------------|----------|-------------|
| `AUTHZ_SUCCESS` | info | Permission granted |
| `AUTHZ_FAILURE` | warning | Permission denied (403) |

### Security Events

| Event Type | Severity | Description |
Expand Down Expand Up @@ -219,6 +226,8 @@ audit_logger.log_contacts_accessed(
| `log_mtls_success()` | MTLS_SUCCESS |
| `log_mtls_failure()` | MTLS_FAILURE |
| `log_mtls_cn_mismatch()` | MTLS_CN_MISMATCH |
| `log_authz_success()` | AUTHZ_SUCCESS |
| `log_authz_failure()` | AUTHZ_FAILURE |
| `log_rate_limit_exceeded()` | RATE_LIMIT_EXCEEDED |
| `log_telemetry_created()` | TELEMETRY_CREATED |
| `log_telemetry_duplicate()` | TELEMETRY_DUPLICATE |
Expand Down Expand Up @@ -397,6 +406,7 @@ docker compose logs gateway | grep "abc123"
| Category | Event Types |
|----------|-------------|
| authentication | AUTH_*, MTLS_*, OAUTH_* |
| authorization | AUTHZ_SUCCESS, AUTHZ_FAILURE |
| security | RATE_LIMIT_EXCEEDED |
| data | TELEMETRY_*, CONTACTS_*, WEATHER_* |
| admin | CONFIG_CHANGED |
Expand Down
192 changes: 192 additions & 0 deletions docs/AUTHORIZATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# Authorization (RBAC) - SkyLink API Gateway

## Overview

SkyLink implements Role-Based Access Control (RBAC) following the **Security by Design** principle of **Least Privilege**. Each role has only the minimum permissions required for its function.

## Roles

| Role | Description | Use Case |
|------|-------------|----------|
| `aircraft_standard` | Default aircraft role | Basic operations (weather, telemetry write) |
| `aircraft_premium` | Premium aircraft | Extended access (+ contacts) |
| `ground_control` | Ground control station | Monitoring operations (read-only) |
| `maintenance` | Maintenance personnel | Diagnostic access |
| `admin` | System administrator | Full access |

## Permissions

| Permission | Description | Resources |
|------------|-------------|-----------|
| `weather:read` | Access weather data | GET /weather/current |
| `contacts:read` | Access contacts data | GET /contacts/ |
| `telemetry:write` | Ingest telemetry | POST /telemetry/ingest |
| `telemetry:read` | Read telemetry | GET /telemetry/events/* |
| `config:read` | Read configuration | Future endpoint |
| `config:write` | Modify configuration | Future endpoint |
| `audit:read` | Read audit logs | Future endpoint |

## Role-Permission Matrix

| Role | weather:read | contacts:read | telemetry:write | telemetry:read | config:read | config:write | audit:read |
|------|:------------:|:-------------:|:---------------:|:--------------:|:-----------:|:------------:|:----------:|
| aircraft_standard | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| aircraft_premium | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| ground_control | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| maintenance | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
| admin | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

## Usage

### Requesting a Token with Role

```bash
# Default role (aircraft_standard)
curl -X POST http://localhost:8000/auth/token \
-H "Content-Type: application/json" \
-d '{"aircraft_id": "550e8400-e29b-41d4-a716-446655440000"}'

# With specific role
curl -X POST http://localhost:8000/auth/token \
-H "Content-Type: application/json" \
-d '{
"aircraft_id": "550e8400-e29b-41d4-a716-446655440000",
"role": "aircraft_premium"
}'
```

### JWT Token Structure

The JWT token includes the role in its claims:

```json
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"aud": "skylink",
"iat": 1703174400,
"exp": 1703175300,
"role": "aircraft_premium"
}
```

### Error Responses

#### 401 Unauthorized
Missing or invalid JWT token.

```json
{
"detail": "Missing Authorization header"
}
```

#### 403 Forbidden
Valid token but insufficient permissions.

```json
{
"detail": "Permission denied: contacts:read required"
}
```

## Implementation

### Adding RBAC to an Endpoint

```python
from fastapi import APIRouter, Depends
from skylink.rbac import require_permission
from skylink.rbac_roles import Permission

router = APIRouter()

@router.get("/protected")
async def protected_endpoint(
token: dict = Depends(require_permission(Permission.WEATHER_READ))
):
# Token is verified and has required permission
return {"message": "Access granted"}
```

### Checking Multiple Permissions

```python
@router.get("/multi-protected")
async def multi_protected(
token: dict = Depends(require_permission(
Permission.TELEMETRY_READ,
Permission.CONFIG_READ
))
):
# Requires BOTH permissions
return {"message": "Access granted"}
```

### Role-Based Restriction

```python
from skylink.rbac import require_role
from skylink.rbac_roles import Role

@router.get("/admin-only")
async def admin_only(
token: dict = Depends(require_role(Role.ADMIN))
):
# Only admin role allowed
return {"message": "Admin access granted"}
```

## Audit Logging

All authorization decisions are logged for security audit:

### Authorization Success
```json
{
"event_type": "AUTHZ_SUCCESS",
"event_category": "authorization",
"severity": "info",
"actor": {"type": "aircraft", "id": "550e8400..."},
"details": {
"role": "aircraft_premium",
"permission": "contacts:read",
"endpoint": "/contacts/"
}
}
```

### Authorization Failure
```json
{
"event_type": "AUTHZ_FAILURE",
"event_category": "authorization",
"severity": "warning",
"actor": {"type": "aircraft", "id": "550e8400..."},
"details": {
"role": "aircraft_standard",
"required_permission": "contacts:read",
"endpoint": "/contacts/"
}
}
```

## Security Considerations

1. **Default Role**: Tokens without explicit role default to `aircraft_standard` (least privilege).

2. **Invalid Roles**: Invalid role values in tokens fall back to `aircraft_standard`.

3. **Role in Token**: Role is embedded in JWT, preventing runtime escalation.

4. **No Role Enumeration**: 403 responses don't reveal which roles would have access.

5. **Authentication vs Authorization**:
- 401 = Authentication failure (no/invalid token)
- 403 = Authorization failure (valid token, wrong permissions)

## Future Enhancements

- Role hierarchy (inheritance)
- Dynamic role assignment from database
- Time-based permissions
- Scope-based access (e.g., specific aircraft only)
Loading