Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API Security Guide

API-level security for orchestration (8080) and worker (8081) endpoints using JWT bearer tokens and API key authentication with permission-based access control.

Security is disabled by default for backward compatibility. Enable it explicitly in configuration.

See also: Auth Documentation Hub for architecture overview, Permissions for route mapping, Configuration for full reference, Testing for E2E test patterns.


Quick Start

1. Generate Keys

cargo run --bin tasker-ctl -- auth generate-keys --output-dir ./keys

2. Generate a Token

cargo run --bin tasker-ctl -- auth generate-token \
  --private-key ./keys/jwt-private-key.pem \
  --permissions "tasks:create,tasks:read,tasks:list,steps:read" \
  --subject my-service \
  --expiry-hours 24

3. Enable Auth in Configuration

In config/tasker/base/orchestration.toml:

[auth]
enabled = true
jwt_public_key_path = "./keys/jwt-public-key.pem"
jwt_issuer = "tasker-core"
jwt_audience = "tasker-api"

4. Use the Token

export TASKER_AUTH_TOKEN=<generated-token>
cargo run --bin tasker-ctl -- task list

Or with curl:

curl -H "Authorization: Bearer $TASKER_AUTH_TOKEN" http://localhost:8080/v1/tasks

Permission Vocabulary

PermissionResourceDescription
tasks:createtasksCreate new tasks
tasks:readtasksRead task details
tasks:listtasksList tasks
tasks:canceltasksCancel running tasks
tasks:context_readtasksRead task context data
steps:readstepsRead workflow step details
steps:resolvestepsManually resolve steps
dlq:readdlqRead DLQ entries
dlq:updatedlqUpdate DLQ investigations
dlq:statsdlqView DLQ statistics
templates:readtemplatesRead task templates
templates:validatetemplatesValidate templates
system:config_readsystemRead system configuration
system:handlers_readsystemRead handler registry
system:analytics_readsystemRead analytics data
worker:config_readworkerRead worker configuration
worker:templates_readworkerRead worker templates

Wildcards

  • tasks:* - All task permissions
  • steps:* - All step permissions
  • dlq:* - All DLQ permissions
  • * - All permissions (superuser)

Show All Permissions

cargo run --bin tasker-ctl -- auth show-permissions

Configuration Reference

Server-Side (orchestration.toml / worker.toml)

[auth]
enabled = true

# JWT Configuration
jwt_issuer = "tasker-core"
jwt_audience = "tasker-api"
jwt_token_expiry_hours = 24

# Key Configuration (one of these):
jwt_public_key_path = "./keys/jwt-public-key.pem"   # File path (preferred)
jwt_public_key = "-----BEGIN RSA PUBLIC KEY-----..." # Inline PEM
# Or set env: TASKER_JWT_PUBLIC_KEY_PATH

# JWKS (for dynamic key rotation)
jwt_verification_method = "jwks"  # "public_key" (default) or "jwks"
jwks_url = "https://auth.example.com/.well-known/jwks.json"
jwks_refresh_interval_seconds = 3600

# Permission validation
permissions_claim = "permissions"   # JWT claim containing permissions
strict_validation = true            # Reject tokens with unknown permissions
log_unknown_permissions = true

# API Key Authentication
api_key_header = "X-API-Key"
api_keys_enabled = true

[[auth.api_keys]]
key = "sk-prod-key-1"
permissions = ["tasks:read", "tasks:list", "steps:read"]
description = "Read-only monitoring service"

[[auth.api_keys]]
key = "sk-admin-key"
permissions = ["*"]
description = "Admin key"

Client-Side (Environment Variables)

VariableDescription
TASKER_AUTH_TOKENBearer token for both APIs
TASKER_ORCHESTRATION_AUTH_TOKENOverride token for orchestration only
TASKER_WORKER_AUTH_TOKENOverride token for worker only
TASKER_API_KEYAPI key (fallback if no token)
TASKER_API_KEY_HEADERCustom header name (default: X-API-Key)

Priority: endpoint-specific token > global token > API key > config file.


JWT Token Structure

{
  "sub": "my-service",
  "iss": "tasker-core",
  "aud": "tasker-api",
  "iat": 1706000000,
  "exp": 1706086400,
  "permissions": [
    "tasks:create",
    "tasks:read",
    "tasks:list",
    "steps:read"
  ],
  "worker_namespaces": []
}

Common Role Patterns

Read-only operator:

permissions: ["tasks:read", "tasks:list", "steps:read", "dlq:read", "dlq:stats"]

Task submitter:

permissions: ["tasks:create", "tasks:read", "tasks:list"]

Ops admin:

permissions: ["tasks:*", "steps:*", "dlq:*", "system:*"]

Worker service:

permissions: ["worker:config_read", "worker:templates_read"]

Superuser:

permissions: ["*"]

Public Endpoints

These endpoints never require authentication:

  • GET /health - Basic health check
  • GET /health/detailed - Detailed health
  • GET /metrics - Prometheus metrics

API Key Authentication

API keys are validated against a configured registry. Each key has its own set of permissions.

# Using API key
curl -H "X-API-Key: sk-prod-key-1" http://localhost:8080/v1/tasks

API keys are simpler than JWTs but have limitations:

  • No expiration (rotate by removing from config)
  • No claims beyond permissions
  • Best for service-to-service communication with static permissions

Error Responses

401 Unauthorized (Missing/Invalid Credentials)

{
  "error": "unauthorized",
  "message": "Missing authentication credentials"
}

403 Forbidden (Insufficient Permissions)

{
  "error": "forbidden",
  "message": "Missing required permission: tasks:create"
}

Migration Guide: Disabled to Enabled

  1. Generate keys and distribute the public key to server config
  2. Generate tokens for each service/user with appropriate permissions
  3. Set enabled = true in auth config
  4. Deploy - services without valid tokens will get 401 responses
  5. Monitor the tasker.auth.failures.total metric for issues

All endpoints remain accessible without auth when enabled = false.


Observability

Structured Logs

  • info on successful authentication (subject, method)
  • warn on authentication failure (error details)
  • warn on permission denial (subject, required permission)

Prometheus Metrics

MetricTypeLabels
tasker.auth.requests.totalCountermethod, result
tasker.auth.failures.totalCounterreason
tasker.permission.denials.totalCounterpermission
tasker.auth.jwt.verification.durationHistogramresult

CLI Auth Commands

# Generate RSA key pair
tasker-ctl auth generate-keys [--output-dir ./keys] [--key-size 2048]

# Generate JWT token
tasker-ctl auth generate-token \
  --permissions tasks:create,tasks:read \
  --subject my-service \
  --private-key ./keys/jwt-private-key.pem \
  --expiry-hours 24

# List all permissions
tasker-ctl auth show-permissions

# Validate a token
tasker-ctl auth validate-token \
  --token <JWT> \
  --public-key ./keys/jwt-public-key.pem

gRPC Authentication

gRPC endpoints support the same authentication methods as REST, using gRPC metadata instead of HTTP headers.

gRPC Ports

ServiceREST PortgRPC Port
Orchestration80809190
Rust Worker80819191

Bearer Token (gRPC)

# Using grpcurl with Bearer token
grpcurl -plaintext \
  -H "Authorization: Bearer $TASKER_AUTH_TOKEN" \
  localhost:9190 tasker.v1.TaskService/ListTasks

API Key (gRPC)

# Using grpcurl with API key
grpcurl -plaintext \
  -H "X-API-Key: sk-prod-key-1" \
  localhost:9190 tasker.v1.TaskService/ListTasks

gRPC Client Configuration

#![allow(unused)]
fn main() {
use tasker_client::grpc_clients::{OrchestrationGrpcClient, GrpcAuthConfig};

// With API key
let client = OrchestrationGrpcClient::connect_with_auth(
    "http://localhost:9190",
    GrpcAuthConfig::ApiKey("sk-prod-key-1".to_string()),
).await?;

// With Bearer token
let client = OrchestrationGrpcClient::connect_with_auth(
    "http://localhost:9190",
    GrpcAuthConfig::Bearer("eyJ...".to_string()),
).await?;
}

gRPC Error Codes

gRPC StatusHTTP EquivalentMeaning
UNAUTHENTICATED401Missing or invalid credentials
PERMISSION_DENIED403Valid credentials but insufficient permissions
NOT_FOUND404Resource not found
UNAVAILABLE503Service unavailable

Public gRPC Endpoints

These endpoints never require authentication:

  • HealthService/CheckHealth - Basic health check
  • HealthService/CheckLiveness - Kubernetes liveness probe
  • HealthService/CheckReadiness - Kubernetes readiness probe
  • HealthService/CheckDetailedHealth - Detailed health metrics

Security Considerations

  • Key storage: Private keys should never be committed to git. Use file paths or environment variables.
  • Token expiry: Set appropriate expiry times. Short-lived tokens (1-24h) are preferred.
  • Least privilege: Grant only the permissions each service needs.
  • Key rotation: Use JWKS for automatic key rotation in production.
  • API key rotation: Remove old keys from config and redeploy.
  • Audit: Monitor tasker.auth.failures.total and tasker.permission.denials.total for anomalies.