# Every client needs modification
-weight: 500;">curl -H "X-Scope-OrgID: team-alpha" http://prometheus:9090/api/v1/query?query=up # Grafana datasources need tenant configuration
# CLI tools need wrapper scripts
# API clients need header injection
# Every client needs modification
-weight: 500;">curl -H "X-Scope-OrgID: team-alpha" http://prometheus:9090/api/v1/query?query=up # Grafana datasources need tenant configuration
# CLI tools need wrapper scripts
# API clients need header injection
# Every client needs modification
-weight: 500;">curl -H "X-Scope-OrgID: team-alpha" http://prometheus:9090/api/v1/query?query=up # Grafana datasources need tenant configuration
# CLI tools need wrapper scripts
# API clients need header injection
-weight: 500;">git clone https://github.com/openlbac/openlbac
cd openlbac # Deploy complete stack: OpenLBAC + Prometheus + Keycloak
-weight: 500;">docker-compose up -d
-weight: 500;">git clone https://github.com/openlbac/openlbac
cd openlbac # Deploy complete stack: OpenLBAC + Prometheus + Keycloak
-weight: 500;">docker-compose up -d
-weight: 500;">git clone https://github.com/openlbac/openlbac
cd openlbac # Deploy complete stack: OpenLBAC + Prometheus + Keycloak
-weight: 500;">docker-compose up -d
# -weight: 500;">docker-compose.yml (relevant sections)
services: lbac-server: image: openlbac/lbac-server:latest ports: - "8090:8090" environment: - DATABASE_URL=postgresql://postgres:password@postgres:5432/openlbac lbac-proxy: image: openlbac/lbac-proxy:latest ports: - "8080:8080" environment: - LBAC_CORE_URL=http://lbac-core:9090 - UPSTREAM_PROMETHEUS_URL=http://prometheus:9090 lbac-core: image: openlbac/lbac-core:latest ports: - "9090:9090" environment: - LBAC_SERVER_URL=http://lbac-server:8090 prometheus: image: prom/prometheus:latest ports: - "9091:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml
# -weight: 500;">docker-compose.yml (relevant sections)
services: lbac-server: image: openlbac/lbac-server:latest ports: - "8090:8090" environment: - DATABASE_URL=postgresql://postgres:password@postgres:5432/openlbac lbac-proxy: image: openlbac/lbac-proxy:latest ports: - "8080:8080" environment: - LBAC_CORE_URL=http://lbac-core:9090 - UPSTREAM_PROMETHEUS_URL=http://prometheus:9090 lbac-core: image: openlbac/lbac-core:latest ports: - "9090:9090" environment: - LBAC_SERVER_URL=http://lbac-server:8090 prometheus: image: prom/prometheus:latest ports: - "9091:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml
# -weight: 500;">docker-compose.yml (relevant sections)
services: lbac-server: image: openlbac/lbac-server:latest ports: - "8090:8090" environment: - DATABASE_URL=postgresql://postgres:password@postgres:5432/openlbac lbac-proxy: image: openlbac/lbac-proxy:latest ports: - "8080:8080" environment: - LBAC_CORE_URL=http://lbac-core:9090 - UPSTREAM_PROMETHEUS_URL=http://prometheus:9090 lbac-core: image: openlbac/lbac-core:latest ports: - "9090:9090" environment: - LBAC_SERVER_URL=http://lbac-server:8090 prometheus: image: prom/prometheus:latest ports: - "9091:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml
# Access Keycloak admin console
open http://localhost:8081 # Default credentials: admin/admin
# Create realm: "observability"
# Create groups: "platform-team", "backend-team", "frontend-team"
# Create users and assign group memberships
# Access Keycloak admin console
open http://localhost:8081 # Default credentials: admin/admin
# Create realm: "observability"
# Create groups: "platform-team", "backend-team", "frontend-team"
# Create users and assign group memberships
# Access Keycloak admin console
open http://localhost:8081 # Default credentials: admin/admin
# Create realm: "observability"
# Create groups: "platform-team", "backend-team", "frontend-team"
# Create users and assign group memberships
oidc: provider_url: "http://localhost:8081/realms/observability" client_id: "openlbac-client" client_secret: "your-client-secret" scopes: ["openid", "profile", "groups"] groups_claim: "groups" policies: - name: "platform-team" groups: ["platform-team"] rules: - label: "namespace" operator: "=~" values: ["production|staging|development"] - name: "backend-team" groups: ["backend-team"] rules: - label: "namespace" operator: "=" values: ["production"] - label: "-weight: 500;">service" operator: "=~" values: ["api|database|cache"] - name: "frontend-team" groups: ["frontend-team"] rules: - label: "namespace" operator: "=" values: ["production"] - label: "-weight: 500;">service" operator: "=" values: ["web"]
oidc: provider_url: "http://localhost:8081/realms/observability" client_id: "openlbac-client" client_secret: "your-client-secret" scopes: ["openid", "profile", "groups"] groups_claim: "groups" policies: - name: "platform-team" groups: ["platform-team"] rules: - label: "namespace" operator: "=~" values: ["production|staging|development"] - name: "backend-team" groups: ["backend-team"] rules: - label: "namespace" operator: "=" values: ["production"] - label: "-weight: 500;">service" operator: "=~" values: ["api|database|cache"] - name: "frontend-team" groups: ["frontend-team"] rules: - label: "namespace" operator: "=" values: ["production"] - label: "-weight: 500;">service" operator: "=" values: ["web"]
oidc: provider_url: "http://localhost:8081/realms/observability" client_id: "openlbac-client" client_secret: "your-client-secret" scopes: ["openid", "profile", "groups"] groups_claim: "groups" policies: - name: "platform-team" groups: ["platform-team"] rules: - label: "namespace" operator: "=~" values: ["production|staging|development"] - name: "backend-team" groups: ["backend-team"] rules: - label: "namespace" operator: "=" values: ["production"] - label: "-weight: 500;">service" operator: "=~" values: ["api|database|cache"] - name: "frontend-team" groups: ["frontend-team"] rules: - label: "namespace" operator: "=" values: ["production"] - label: "-weight: 500;">service" operator: "=" values: ["web"]
# Platform team member (full access)
-weight: 500;">curl -H "Authorization: Bearer $PLATFORM_TOKEN" \ "http://localhost:8080/api/v1/query?query=up" # Backend team member (-weight: 500;">service-filtered)
-weight: 500;">curl -H "Authorization: Bearer $BACKEND_TOKEN" \ "http://localhost:8080/api/v1/query?query=up" # Frontend team member (web -weight: 500;">service only)
-weight: 500;">curl -H "Authorization: Bearer $FRONTEND_TOKEN" \ "http://localhost:8080/api/v1/query?query=up"
# Platform team member (full access)
-weight: 500;">curl -H "Authorization: Bearer $PLATFORM_TOKEN" \ "http://localhost:8080/api/v1/query?query=up" # Backend team member (-weight: 500;">service-filtered)
-weight: 500;">curl -H "Authorization: Bearer $BACKEND_TOKEN" \ "http://localhost:8080/api/v1/query?query=up" # Frontend team member (web -weight: 500;">service only)
-weight: 500;">curl -H "Authorization: Bearer $FRONTEND_TOKEN" \ "http://localhost:8080/api/v1/query?query=up"
# Platform team member (full access)
-weight: 500;">curl -H "Authorization: Bearer $PLATFORM_TOKEN" \ "http://localhost:8080/api/v1/query?query=up" # Backend team member (-weight: 500;">service-filtered)
-weight: 500;">curl -H "Authorization: Bearer $BACKEND_TOKEN" \ "http://localhost:8080/api/v1/query?query=up" # Frontend team member (web -weight: 500;">service only)
-weight: 500;">curl -H "Authorization: Bearer $FRONTEND_TOKEN" \ "http://localhost:8080/api/v1/query?query=up"
rate(http_requests_total{-weight: 500;">status="200"}[5m])
rate(http_requests_total{-weight: 500;">status="200"}[5m])
rate(http_requests_total{-weight: 500;">status="200"}[5m])
rate(http_requests_total{-weight: 500;">status="200", namespace="production", -weight: 500;">service=~"api|database|cache"}[5m])
rate(http_requests_total{-weight: 500;">status="200", namespace="production", -weight: 500;">service=~"api|database|cache"}[5m])
rate(http_requests_total{-weight: 500;">status="200", namespace="production", -weight: 500;">service=~"api|database|cache"}[5m])
rate(http_requests_total{-weight: 500;">status="200", namespace="production", -weight: 500;">service="web"}[5m])
rate(http_requests_total{-weight: 500;">status="200", namespace="production", -weight: 500;">service="web"}[5m])
rate(http_requests_total{-weight: 500;">status="200", namespace="production", -weight: 500;">service="web"}[5m])
# Grafana datasource configuration
apiVersion: v1
kind: ConfigMap
metadata: name: grafana-datasources
data: prometheus.yml: | apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://lbac-proxy:8080 # Changed from prometheus:9090 access: proxy jsonData: httpHeaderName1: "Authorization" secureJsonData: httpHeaderValue1: "Bearer $GRAFANA_OIDC_TOKEN"
# Grafana datasource configuration
apiVersion: v1
kind: ConfigMap
metadata: name: grafana-datasources
data: prometheus.yml: | apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://lbac-proxy:8080 # Changed from prometheus:9090 access: proxy jsonData: httpHeaderName1: "Authorization" secureJsonData: httpHeaderValue1: "Bearer $GRAFANA_OIDC_TOKEN"
# Grafana datasource configuration
apiVersion: v1
kind: ConfigMap
metadata: name: grafana-datasources
data: prometheus.yml: | apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://lbac-proxy:8080 # Changed from prometheus:9090 access: proxy jsonData: httpHeaderName1: "Authorization" secureJsonData: httpHeaderValue1: "Bearer $GRAFANA_OIDC_TOKEN"
# -weight: 500;">docker-compose.override.yml
services: lbac-proxy: deploy: replicas: 3 nginx: image: nginx:alpine ports: - "8080:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf
# -weight: 500;">docker-compose.override.yml
services: lbac-proxy: deploy: replicas: 3 nginx: image: nginx:alpine ports: - "8080:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf
# -weight: 500;">docker-compose.override.yml
services: lbac-proxy: deploy: replicas: 3 nginx: image: nginx:alpine ports: - "8080:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf
upstream lbac_proxies { server lbac-proxy-1:8080; server lbac-proxy-2:8080; server lbac-proxy-3:8080;
} server { listen 80; location / { proxy_pass http://lbac_proxies; proxy_set_header Authorization $http_authorization; }
}
upstream lbac_proxies { server lbac-proxy-1:8080; server lbac-proxy-2:8080; server lbac-proxy-3:8080;
} server { listen 80; location / { proxy_pass http://lbac_proxies; proxy_set_header Authorization $http_authorization; }
}
upstream lbac_proxies { server lbac-proxy-1:8080; server lbac-proxy-2:8080; server lbac-proxy-3:8080;
} server { listen 80; location / { proxy_pass http://lbac_proxies; proxy_set_header Authorization $http_authorization; }
}
# prometheus.yml
global: scrape_interval: 15s scrape_configs: - job_name: 'lbac-proxy' static_configs: - targets: ['lbac-proxy:8080'] metrics_path: '/metrics' - job_name: 'lbac-core' static_configs: - targets: ['lbac-core:9090'] metrics_path: '/metrics'
# prometheus.yml
global: scrape_interval: 15s scrape_configs: - job_name: 'lbac-proxy' static_configs: - targets: ['lbac-proxy:8080'] metrics_path: '/metrics' - job_name: 'lbac-core' static_configs: - targets: ['lbac-core:9090'] metrics_path: '/metrics'
# prometheus.yml
global: scrape_interval: 15s scrape_configs: - job_name: 'lbac-proxy' static_configs: - targets: ['lbac-proxy:8080'] metrics_path: '/metrics' - job_name: 'lbac-core' static_configs: - targets: ['lbac-core:9090'] metrics_path: '/metrics'
# config/audit.yml
audit: enabled: true sink_type: "elasticsearch" elasticsearch: endpoint: "http://elasticsearch:9200" index: "openlbac-audit" events: - "query_execution" - "policy_violation" - "authentication_failure" - "authorization_decision"
# config/audit.yml
audit: enabled: true sink_type: "elasticsearch" elasticsearch: endpoint: "http://elasticsearch:9200" index: "openlbac-audit" events: - "query_execution" - "policy_violation" - "authentication_failure" - "authorization_decision"
# config/audit.yml
audit: enabled: true sink_type: "elasticsearch" elasticsearch: endpoint: "http://elasticsearch:9200" index: "openlbac-audit" events: - "query_execution" - "policy_violation" - "authentication_failure" - "authorization_decision"
# Check token structure
echo $TOKEN | base64 -d | jq . # Verify groups claim exists
# Ensure issuer matches provider_url
# Check client_id in token audience
# Check token structure
echo $TOKEN | base64 -d | jq . # Verify groups claim exists
# Ensure issuer matches provider_url
# Check client_id in token audience
# Check token structure
echo $TOKEN | base64 -d | jq . # Verify groups claim exists
# Ensure issuer matches provider_url
# Check client_id in token audience
# Verify labels exist in your metrics
-weight: 500;">curl http://prometheus:9090/api/v1/labels # Test policy rules manually
-weight: 500;">curl "http://localhost:8090/api/v1/policies/test" \ -d '{"query": "up", "user_groups": ["backend-team"]}'
# Verify labels exist in your metrics
-weight: 500;">curl http://prometheus:9090/api/v1/labels # Test policy rules manually
-weight: 500;">curl "http://localhost:8090/api/v1/policies/test" \ -d '{"query": "up", "user_groups": ["backend-team"]}'
# Verify labels exist in your metrics
-weight: 500;">curl http://prometheus:9090/api/v1/labels # Test policy rules manually
-weight: 500;">curl "http://localhost:8090/api/v1/policies/test" \ -d '{"query": "up", "user_groups": ["backend-team"]}'
# config/performance.yml
cache: policy_cache_ttl: 300s query_cache_ttl: 60s optimization: max_rule_complexity: 10 parallel_policy_evaluation: true
# config/performance.yml
cache: policy_cache_ttl: 300s query_cache_ttl: 60s optimization: max_rule_complexity: 10 parallel_policy_evaluation: true
# config/performance.yml
cache: policy_cache_ttl: 300s query_cache_ttl: 60s optimization: max_rule_complexity: 10 parallel_policy_evaluation: true - Docker and Docker Compose installed
- An existing Prometheus instance (or willingness to deploy one)
- An OIDC provider with group claims (Keycloak, Okta, Auth0)
- Basic understanding of PromQL and observability concepts - lbac_proxy_query_duration_seconds - Query rewriting latency
- lbac_proxy_queries_total - Request rate and error rate
- lbac_core_policy_updates_total - Policy propagation health
- lbac_core_connected_proxies - Proxy connectivity -weight: 500;">status - User identity and group membership
- Original query and rewritten query
- Data sources accessed
- Timestamp and request metadata