Team-Based Deployment Guide
What You'll Learn
By the end of this guide, you will understand how to:
- Organize clusters using team-based labels for multi-tenant isolation
- Create dashboards filtered for specific teams and environments
- Build custom navigation menus tailored to team workflows
- Implement REGO authorization policies for secure access control
This is an integration guide that demonstrates how SPOG's four key components work together to create secure, team-isolated views of your PowerDNS infrastructure.
The Business Scenario
You are a platform engineer at a company managing PowerDNS infrastructure for multiple application teams. Each team:
- Manages their own set of DNS clusters across multiple environments (development, staging, production)
- Needs isolated views showing only their clusters
- Has different access levels based on roles (Team Lead, Developer, Operator)
- Requires custom dashboards and navigation relevant to their workflows
Your goal is to deploy SPOG so that:
- The DevOps team sees only their clusters with appropriate dashboards and tools
- The Platform team sees their own separate set of clusters
- Team members have appropriate permissions based on their roles
- Developers cannot access production environments
- Only operators can perform infrastructure operations like restarting instances
This guide shows you how to implement this complete team-based isolation using SPOG's integrated architecture.
Following Along
Want to deploy this example in your own Kubernetes cluster? This section provides everything you need to follow along step-by-step.
Note: The components work together as a system—you'll need to complete all four steps in this guide before everything connects and functions properly.
How Will You Access Glass UI?
Prerequisites
Before starting, ensure you have:
- Kubernetes cluster (v1.24+)
- Ingress controller installed (e.g., nginx-ingress)
- Helm 3.8+ installed
- kubectl configured to access your cluster
- Registry credentials for
registry.open-xchange.com
Download Example Files
Download all configuration files for this guide:
Download Team-Based Deployment Examples
This archive contains:
Infrastructure values files:
controlplane-quickstart.yaml - Minimal controlplane with NATS hub
powerdns-quickstart.yaml - PowerDNS cluster with recursor and dnsdist
Glass configuration files:
- Label configurations:
team-based-labels-devops-prod.yaml, team-based-labels-devops-staging.yaml, team-based-labels-devops-dev.yaml, team-based-labels-platform-prod.yaml
- Dashboard configuration:
team-based-dashboard.yaml
- Navigation configuration:
team-based-navigation.yaml
- REGO policy configuration:
team-based-rego.yaml
Registry Authentication
Set up your registry credentials and log in to the OCI registry:
| Bash |
|---|
| # Set your credentials
export REGISTRY_USERNAME="your-username"
export REGISTRY_PASSWORD="your-password"
|
| Bash |
|---|
| export GLASS_HOSTNAME="glass.example.com" # Replace with your domain
|
| Bash |
|---|
| export NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
|
| Bash |
|---|
| # Login to Helm registry
helm registry login registry.open-xchange.com \
--username "$REGISTRY_USERNAME" \
--password "$REGISTRY_PASSWORD"
|
Create Namespaces and Image Pull Secrets
Create the namespaces and image pull secrets for all components:
| Bash |
|---|
| # Controlplane namespace
kubectl create namespace controlplane
kubectl create secret docker-registry registry-credentials \
--docker-server=registry.open-xchange.com \
--docker-username="$REGISTRY_USERNAME" \
--docker-password="$REGISTRY_PASSWORD" \
--namespace=controlplane
# Create namespaces for each team cluster
for ns in devops-prod devops-staging devops-dev platform-prod; do
kubectl create namespace $ns
kubectl create secret docker-registry registry-credentials \
--docker-server=registry.open-xchange.com \
--docker-username="$REGISTRY_USERNAME" \
--docker-password="$REGISTRY_PASSWORD" \
--namespace=$ns
done
|
Deploy Infrastructure
The following commands use the values files from the downloaded zip. Make sure you're in the directory where you extracted the files.
Install PowerDNS CRDs
| Bash |
|---|
| helm install powerdns-crds \
oci://registry.open-xchange.com/cloudcontrol/powerdns-crds \
--version "3.1.13"
|
Deploy Controlplane
| Bash |
|---|
| helm install team-controlplane \
oci://registry.open-xchange.com/cloudcontrol/controlplane \
--version "3.1.13" \
--namespace controlplane \
--set global.imagePullSecretsList[0]=registry-credentials \
-f controlplane-quickstart.yaml
|
Deploy PowerDNS Clusters
Deploy a PowerDNS instance in each namespace:
| Bash |
|---|
| # DevOps Production
helm install devops-prod \
oci://registry.open-xchange.com/cloudcontrol/powerdns \
--version "3.1.13" \
--namespace devops-prod \
--set global.imagePullSecretsList[0]=registry-credentials \
-f powerdns-quickstart.yaml
# DevOps Staging
helm install devops-staging \
oci://registry.open-xchange.com/cloudcontrol/powerdns \
--version "3.1.13" \
--namespace devops-staging \
--set global.imagePullSecretsList[0]=registry-credentials \
-f powerdns-quickstart.yaml
# DevOps Development
helm install devops-dev \
oci://registry.open-xchange.com/cloudcontrol/powerdns \
--version "3.1.13" \
--namespace devops-dev \
--set global.imagePullSecretsList[0]=registry-credentials \
-f powerdns-quickstart.yaml
# Platform Production
helm install platform-prod \
oci://registry.open-xchange.com/cloudcontrol/powerdns \
--version "3.1.13" \
--namespace platform-prod \
--set global.imagePullSecretsList[0]=registry-credentials \
-f powerdns-quickstart.yaml
|
Now you're ready to follow along with each step below. Deployment commands are provided after each configuration section.
Architecture Overview
This team-based deployment in SPOG creates secure, isolated views for different user types through the integration of four components: Labels, Dashboards, Navigation, and REGO authorization.
Cluster Organization by Labels
Each cluster is organized using three-dimensional labeling:
| Cluster ID |
Team |
Environment |
Role |
| DevOps Team Clusters |
|
|
|
devops-prod-auth-01 |
devops |
production |
authoritative |
devops-staging-rec-01 |
devops |
staging |
recursor |
devops-dev-auth-01 |
devops |
development |
authoritative |
| Platform Team Clusters |
|
|
|
platform-prod-auth-01 |
platform |
production |
authoritative |
Labels are the foundation that enables:
| Capability |
Example |
Purpose |
| Dashboard filtering |
team = "devops" |
Filter widgets to show only relevant clusters |
| REGO authorization |
input.cluster.labels.team == input.user.team |
Control access based on team membership |
| Multi-dimensional organization |
team, environment, role |
Flexible taxonomy for any organizational structure |
| Scalability |
Simple team isolation → Complex multi-tenant architectures |
Grow from basic to sophisticated access control |
User Types and Access Levels
This deployment defines four user types with different access patterns:
| User Type |
Teams |
Environments |
Operations |
Dashboard Access |
| DevOps Team Lead |
DevOps |
All (dev, staging, prod) |
Read + Write (operator) |
All DevOps dashboards |
| DevOps Developer |
DevOps |
dev, staging only |
Read only (observer) |
DevOps non-prod dashboards |
| Platform Engineer |
Platform |
All (dev, staging, prod) |
Read + Write (operator) |
Platform dashboards only |
| Global Administrator |
All |
All |
Full admin bypass |
All dashboards |
Access Decision Logic
Authorization follows a hierarchical decision tree:
| User |
Cluster |
Operation |
Team Check |
Env Check |
Role Check |
Result |
| DevOps Developer |
devops-prod-auth-01 |
read_logs |
✓ devops |
✗ no production |
- |
DENIED |
| DevOps Developer |
devops-staging-rec-01 |
read_logs |
✓ devops |
✓ staging |
✓ observer |
ALLOWED |
| DevOps Developer |
devops-staging-rec-01 |
restart_instance |
✓ devops |
✓ staging |
✗ no operator |
DENIED |
| DevOps Team Lead |
devops-prod-auth-01 |
restart_instance |
✓ devops |
✓ production |
✓ operator |
ALLOWED |
| Platform Engineer |
devops-prod-auth-01 |
read_logs |
✗ platform≠devops |
- |
- |
DENIED |
| Global Admin |
any-cluster |
any-operation |
bypass |
bypass |
bypass |
ALLOWED |
Step 1: Label Your Clusters
The first step in team-based deployment is applying consistent labels to your user plane clusters. Labels define cluster identity and enable all subsequent filtering and access control.
Labels define cluster identity through key-value pairs. For team-based deployment, we use three primary label dimensions: team (ownership), environment (lifecycle stage), and role (DNS service type).
Example Cluster Label Configurations
Here are examples showing how to label clusters for different teams and environments:
DevOps Team - Production Authoritative:
| YAML |
|---|
| clusterId: "devops-prod-auth-01"
labels:
team: "devops" # Team ownership - enables team-based filtering
environment: "production" # Deployment stage - restricts access to authorized users
role: "authoritative" # DNS service type - for service-specific filtering
|
DevOps Team - Staging Recursor:
| YAML |
|---|
| clusterId: "devops-staging-rec-01"
labels:
team: "devops" # Team ownership - enables team-based filtering
environment: "staging" # Deployment stage - accessible to developers
role: "recursor" # DNS service type - recursive resolver
|
DevOps Team - Development Authoritative:
| YAML |
|---|
| clusterId: "devops-dev-auth-01"
labels:
team: "devops" # Team ownership - enables team-based filtering
environment: "development" # Deployment stage - unrestricted for team members
role: "authoritative" # DNS service type - authoritative nameserver
|
Platform Team - Production Authoritative:
| YAML |
|---|
| clusterId: "platform-prod-auth-01"
labels:
team: "platform" # Team ownership - different from DevOps team
environment: "production" # Deployment stage - restricts access to authorized users
role: "authoritative" # DNS service type - for service-specific filtering
|
Label Strategy
The example demonstrates a three-dimensional labeling strategy:
-
Primary filter: team - This is the main isolation boundary. Dashboards filter by team, REGO policies check team membership.
-
Secondary filter: environment - Within a team, clusters are grouped by lifecycle stage. This enables:
- Restricting developers to non-production environments
- Creating environment-specific dashboards
-
Implementing different policies per environment
-
Tertiary dimension: role - DNS service type provides additional organization and filtering capability.
Deploy Step 1: Glass Instrumentation with Labels
Deploy Glass Instrumentation to each cluster with the appropriate label configuration:
| Bash |
|---|
| # DevOps Production
helm install glass-instrumentation \
oci://registry.open-xchange.com/cc-glass/glass-instrumentation \
--version "1.0.0" \
--namespace devops-prod \
--set global.imagePullSecretsList[0]=registry-credentials \
-f team-based-labels-devops-prod.yaml
# DevOps Staging
helm install glass-instrumentation \
oci://registry.open-xchange.com/cc-glass/glass-instrumentation \
--version "1.0.0" \
--namespace devops-staging \
--set global.imagePullSecretsList[0]=registry-credentials \
-f team-based-labels-devops-staging.yaml
# DevOps Development
helm install glass-instrumentation \
oci://registry.open-xchange.com/cc-glass/glass-instrumentation \
--version "1.0.0" \
--namespace devops-dev \
--set global.imagePullSecretsList[0]=registry-credentials \
-f team-based-labels-devops-dev.yaml
# Platform Production
helm install glass-instrumentation \
oci://registry.open-xchange.com/cc-glass/glass-instrumentation \
--version "1.0.0" \
--namespace platform-prod \
--set global.imagePullSecretsList[0]=registry-credentials \
-f team-based-labels-platform-prod.yaml
|
Once all steps are complete, each cluster will be visible in SPOG with its configured labels.
Step 2: Create Team Dashboard
With clusters labeled, the next step is creating dashboards that automatically filter to show only team-relevant clusters. Dashboards are where users spend most of their time, so proper filtering is essential for team isolation.
Example: DevOps Team Dashboard Configuration
| YAML |
|---|
| # Example: Team-Based Dashboard Configuration
globalConfig:
dashboards:
# Dashboard 1: DevOps Team Overview
# Main dashboard showing all DevOps team clusters
devops-overview:
title: "DevOps Team Dashboard"
description: "PowerDNS clusters managed by the DevOps team"
url: /team/devops
requires:
- "dashboard_devops_overview" # REGO permission flag
graphs:
# Widget 1: Tree table showing all DevOps clusters
- widget: "cc-state-tree-table"
title: "DevOps Cluster State"
args:
# Filter: Only show clusters with team="devops" label
filter: 'team = "devops"'
# Widget 2: Heatmap showing cluster readiness
- widget: "cc-state-readiness-heatmap"
title: "DevOps Cluster Health"
args:
filter: 'team = "devops"'
# Dashboard 2: DevOps Production View
# Filtered view showing only production clusters
devops-production:
title: "DevOps Production"
description: "Production PowerDNS clusters for DevOps team"
url: /team/devops/production
requires:
- "dashboard_devops_production"
graphs:
- widget: "cc-state-tree-table"
title: "Production Clusters"
args:
# Multiple conditions: team AND environment
filter: 'team = "devops" and environment = "production"'
- widget: "cc-state-readiness-pie-charts"
title: "Production Readiness Distribution"
args:
filter: 'team = "devops" and environment = "production"'
# Dashboard 3: DevOps by Environment
# Separate view for each environment (dev, staging, prod)
devops-by-environment:
title: "DevOps Environments"
description: "DevOps clusters organized by environment"
url: /team/devops/environments
requires:
- "dashboard_devops_environments"
graphs:
# Development clusters
- widget: "cc-state-tree-table"
title: "Development"
args:
filter: 'team = "devops" and environment = "development"'
# Staging clusters
- widget: "cc-state-tree-table"
title: "Staging"
args:
filter: 'team = "devops" and environment = "staging"'
# Production clusters
- widget: "cc-state-tree-table"
title: "Production"
args:
filter: 'team = "devops" and environment = "production"'
# Dashboard 4: Platform Team Overview
# Main dashboard showing all Platform team clusters
platform-overview:
title: "Platform Team Dashboard"
description: "PowerDNS clusters managed by the Platform team"
url: /team/platform
requires:
- "dashboard_platform_overview" # REGO permission flag
graphs:
# Widget 1: Tree table showing all Platform clusters
- widget: "cc-state-tree-table"
title: "Platform Cluster State"
args:
filter: 'team = "platform"'
# Widget 2: Heatmap showing cluster readiness
- widget: "cc-state-readiness-heatmap"
title: "Platform Cluster Health"
args:
filter: 'team = "platform"'
# Dashboard 5: Platform Production View
# Filtered view showing only production clusters
platform-production:
title: "Platform Production"
description: "Production PowerDNS clusters for Platform team"
url: /team/platform/production
requires:
- "dashboard_platform_production"
graphs:
- widget: "cc-state-tree-table"
title: "Production Clusters"
args:
filter: 'team = "platform" and environment = "production"'
- widget: "cc-state-readiness-pie-charts"
title: "Production Readiness Distribution"
args:
filter: 'team = "platform" and environment = "production"'
# Dashboard 6: Platform by Environment
# Separate view for each environment (dev, staging, prod)
platform-by-environment:
title: "Platform Environments"
description: "Platform clusters organized by environment"
url: /team/platform/environments
requires:
- "dashboard_platform_environments"
graphs:
# Development clusters
- widget: "cc-state-tree-table"
title: "Development"
args:
filter: 'team = "platform" and environment = "development"'
# Staging clusters
- widget: "cc-state-tree-table"
title: "Staging"
args:
filter: 'team = "platform" and environment = "staging"'
# Production clusters
- widget: "cc-state-tree-table"
title: "Production"
args:
filter: 'team = "platform" and environment = "production"'
# Dashboard 7: Global Overview (Admin Only)
# Shows all clusters across all teams
global-overview:
title: "Global Cluster Overview"
description: "All PowerDNS clusters across all teams"
url: /global/all-clusters
requires:
- "dashboard_global_admin" # Only admins can see all clusters
graphs:
- widget: "cc-state-tree-table"
title: "All Clusters"
args:
filter: '' # No filter - show everything
- widget: "cc-state-readiness-heatmap"
title: "Global Cluster Health"
args:
filter: ''
# Dashboard 8: Global by Team (Admin Only)
# Shows separate widgets for each team
global-by-team:
title: "Global View by Team"
description: "All teams and their clusters"
url: /global/by-team
requires:
- "dashboard_global_admin"
graphs:
# DevOps team clusters
- widget: "cc-state-tree-table"
title: "DevOps Team"
args:
filter: 'team = "devops"'
# Platform team clusters
- widget: "cc-state-tree-table"
title: "Platform Team"
args:
filter: 'team = "platform"'
# Readiness summary across all teams
- widget: "cc-state-readiness-pie-charts"
title: "Overall Readiness by Team"
args:
filter: ''
|
Dashboard Breakdown
The example creates eight dashboards organized by team and access level:
DevOps Team Dashboards
1. DevOps Team Overview (/team/devops)
Main dashboard showing all DevOps clusters with two widgets:
| YAML |
|---|
| filter: 'team = "devops"'
|
- Tree table: Shows cluster state for all DevOps clusters
- Readiness heatmap: Visual health overview across all environments
Shows all clusters where team label equals "devops" - production, staging, and development.
2. DevOps Production (/team/devops/production)
Production-only view with stricter filtering:
| YAML |
|---|
| filter: 'team = "devops" and environment = "production"'
|
- Tree table: Production clusters only
- Readiness pie charts: Distribution of production cluster health
Combines two conditions: must be DevOps team AND production environment.
3. DevOps by Environment (/team/devops/environments)
Side-by-side environment comparison with three widgets:
| YAML |
|---|
| # Three separate widgets, each filtering one environment
filter: 'team = "devops" and environment = "development"'
filter: 'team = "devops" and environment = "staging"'
filter: 'team = "devops" and environment = "production"'
|
Each widget shows a tree table for its respective environment, making it easy to compare dev/staging/prod side-by-side.
4. Platform Team Overview (/team/platform)
Main dashboard showing all Platform clusters:
| YAML |
|---|
| filter: 'team = "platform"'
|
- Tree table: Shows cluster state for all Platform clusters
- Readiness heatmap: Visual health overview
Shows all clusters where team label equals "platform".
5. Platform Production (/team/platform/production)
Production-only view for Platform team:
| YAML |
|---|
| filter: 'team = "platform" and environment = "production"'
|
- Tree table: Platform production clusters
- Readiness pie charts: Production health distribution
6. Platform by Environment (/team/platform/environments)
Environment comparison for Platform team:
| YAML |
|---|
| filter: 'team = "platform" and environment = "development"'
filter: 'team = "platform" and environment = "staging"'
filter: 'team = "platform" and environment = "production"'
|
Three tree table widgets for side-by-side environment comparison.
Global Admin Dashboards
7. Global Overview (/global/all-clusters)
Complete system view showing all clusters across all teams:
| YAML |
|---|
| filter: '' # No filter - shows everything
|
- Tree table: All clusters in the system
- Readiness heatmap: System-wide health overview
Only accessible to global administrators.
8. Global by Team (/global/by-team)
Cross-team comparison view:
| YAML |
|---|
| # Separate widgets for each team
filter: 'team = "devops"'
filter: 'team = "platform"'
filter: '' # Overall readiness across all teams
|
- Tree table (DevOps): All DevOps team clusters
- Tree table (Platform): All Platform team clusters
- Readiness pie charts: Overall health distribution across all teams
Provides global administrators with team-segmented visibility for cross-team operations.
Dashboard Permissions
Each dashboard includes a requires field that references REGO permission flags:
| YAML |
|---|
| requires:
- "dashboard_devops_overview"
|
This works as follows:
1. User attempts to access dashboard
2. Glass UI queries REGO policy engine: "Does this user have dashboard_devops_overview permission?"
3. REGO evaluates policies (defined in Step 4) and returns true/false
4. If true: dashboard loads. If false: user sees "Access Denied"
Permission Naming Convention: Dashboard permissions follow the pattern dashboard_{team}_{view}:
- dashboard_devops_overview - DevOps team overview dashboard
- dashboard_devops_production - DevOps production-only view
- dashboard_platform_overview - Platform team overview dashboard
- dashboard_global_admin - Global administrator dashboards
Forward Reference: These dashboard permission flags are defined in Step 4 (REGO Policies).
For now, understand that this creates a security boundary - only authorized users see the dashboard.
Integration Point: Labels Enable Dashboards
Notice the connection:
- Step 1 labeled clusters with
team: "devops"
- Step 2 creates dashboards that filter by
team = "devops"
- Result: Dashboards automatically show the right clusters
This is the first integration point where labels drive behavior. The next step adds navigation so users can easily access these dashboards.
Deployment Note
Steps 2, 3, and 4 (Dashboards, Navigation, and REGO Policies) all configure the Glass UI. These configurations are provided in separate values files (team-based-dashboard.yaml, team-based-navigation.yaml, team-based-rego.yaml) and deployed together after Step 4 using multiple -f flags.
With dashboards created, you need a way for users to access them. Navigation provides the menu structure that guides users to their team-specific dashboards and tools.
Navigation is organized in three levels (Menu → Section → Item) grouped by team. Each menu contains sections that organize related dashboards and tools.
| YAML |
|---|
| # Example: Team-Based Navigation Configuration
# This example shows how to create a custom navigation menu for a specific team.
#
# The DevOps team gets a tailored menu structure focused on their workflows.
globalConfig:
navigation:
menus:
# Menu 1: DevOps Team Menu
- name: "DevOps Team"
sections:
# Section 1: Dashboard Links
- name: "Dashboards"
items:
# Link to main team dashboard
- name: "Team Overview"
url: "/team/devops"
description: "All DevOps clusters"
# Link to production-only view
- name: "Production"
url: "/team/devops/production"
description: "Production clusters only"
# Link to environment breakdown
- name: "By Environment"
url: "/team/devops/environments"
description: "Dev, Staging, Prod views"
# Section 2: External Links (EXAMPLE ONLY - these URLs are fictional)
- name: "Resources"
items:
# Example: Link to team runbook
- name: "Team Runbook"
url: "https://docs.example.com/devops/runbook"
description: "DevOps operational procedures"
external: true
requires:
- "navigation_devops_resources"
# Example: Link to team documentation
- name: "Team Wiki"
url: "https://wiki.example.com/devops"
description: "DevOps team wiki"
external: true
requires:
- "navigation_devops_resources"
# Menu 2: Platform Team Menu
- name: "Platform Team"
sections:
# Section 1: Dashboard Links
- name: "Dashboards"
items:
# Link to main team dashboard
- name: "Team Overview"
url: "/team/platform"
description: "All Platform clusters"
# Link to production-only view
- name: "Production"
url: "/team/platform/production"
description: "Production clusters only"
# Link to environment breakdown
- name: "By Environment"
url: "/team/platform/environments"
description: "Dev, Staging, Prod views"
# Section 2: External Links (EXAMPLE ONLY - these URLs are fictional)
- name: "Resources"
items:
# Example: Link to team runbook
- name: "Team Runbook"
url: "https://docs.example.com/platform/runbook"
description: "Platform operational procedures"
external: true
requires:
- "navigation_platform_resources"
# Example: Link to team documentation
- name: "Team Wiki"
url: "https://wiki.example.com/platform"
description: "Platform team wiki"
external: true
requires:
- "navigation_platform_resources"
# Menu 3: Global Admin Menu
- name: "Global Admin"
sections:
# Section 1: Global Dashboard Links
- name: "Dashboards"
items:
# Link to global overview dashboard
- name: "Global Overview"
url: "/global/all-clusters"
description: "All clusters across all teams"
# Link to by-team view
- name: "View by Team"
url: "/global/by-team"
description: "Clusters organized by team"
# Section 2: All Teams Quick Access
- name: "Team Dashboards"
items:
- name: "DevOps Team"
url: "/team/devops"
description: "DevOps team dashboard"
- name: "Platform Team"
url: "/team/platform"
description: "Platform team dashboard"
# Note: The default "Tools" menu (DNS Query, Cache Management) is automatically
# appended after these custom menus.
# Navigation Visibility:
# - Navigation menus can be conditionally displayed based on user permissions
# - REGO policies control which menus and items a user sees
# - Users only see navigation items they have permission to access
#
# Integration with Dashboards:
# - Menu items link to dashboard URLs defined in team-based-dashboard.yaml
# - Example: "/team/devops" links to devops-overview dashboard
|
Navigation Breakdown
The example creates three custom menus for different teams and access levels:
1. DevOps Team Menu
Primary navigation for DevOps team members:
Dashboards Section:
- Links to all three DevOps team dashboards
- URLs match dashboard url fields from Step 2 (/team/devops, /team/devops/production, etc.)
- Descriptions help users understand what each dashboard shows
Resources Section:
- Example external links (fictional URLs for demonstration)
- Links to team runbook and wiki
- Marked with external: true to indicate they open in new tabs
2. Platform Team Menu
Primary navigation for Platform team members:
Dashboards Section:
- Links to all three Platform team dashboards
- URLs match Platform dashboard url fields (/team/platform, /team/platform/production, etc.)
- Same structure as DevOps menu but for Platform team resources
Resources Section:
- Example external links (fictional URLs for demonstration)
- Links to team runbook and wiki
3. Global Admin Menu
Administrative navigation for global administrators:
Dashboards Section:
- Global Overview: All clusters across all teams (/global/all-clusters)
- View by Team: Team-segmented view (/global/by-team)
Team Dashboards Section:
- Quick access links to all team dashboards
- Allows admins to view any team's perspective
Default Tools Menu
The default "Tools" menu is automatically appended after custom menus and provides:
- DNS Query: Test DNS resolution against your clusters
- Flush Cache: Clear DNS cache across clusters
This menu is included by default (globalConfig.defaults.enabled: true) so you don't need to add a custom operations menu for these common tasks.
Navigation URL Mapping
Navigation item URLs link to dashboard URL patterns:
| YAML |
|---|
| # Dashboard configuration (Step 2)
dashboards:
devops-overview:
url: /team/devops
# Navigation item (Step 3)
items:
- name: "Team Overview"
url: "/team/devops"
|
When a user clicks "Team Overview" in the navigation:
- Glass UI routes to
/team/devops
- Finds dashboard with matching
url: /team/devops
- Loads dashboard configuration and renders widgets
- Widgets apply filter
team = "devops" and display data
Placeholder URLs
When using placeholder dashboards (see "Refactoring with Placeholders"), navigation items use concrete URLs (/team/devops) that match parameterized dashboard patterns (/team/:team).
Navigation Visibility and Permissions
Navigation items are automatically shown or hidden based on user permissions:
- Dashboard links (e.g.,
url: "/team/devops") - visible only if user can access that dashboard
- External links (e.g., team wikis) - can be controlled with navigation item
requires field
- Internal actions (e.g.,
/dns-query) - protected by application-level permissions
Navigation items can optionally specify their own requires field for additional control:
| YAML |
|---|
| - name: "Team Runbook"
url: "https://docs.example.com/devops/runbook"
external: true
requires:
- "navigation_devops_resources"
|
Result: Each user sees only the menus and links they have permission to access.
Integration Point: Navigation Links to Dashboards
Notice the connection:
- Step 2 created dashboard with
url: /team/devops
- Step 3 creates navigation item with
url: "/team/devops"
- Result: Clicking navigation item takes user to team dashboard
This is the second integration point. The next step adds access control so only authorized users can see and use these navigation items and dashboards.
Step 4: Set REGO Policies
With dashboards and navigation in place, the final critical step is implementing authorization policies. REGO policies ensure that users can only access their team's clusters and perform operations appropriate to their roles.
REGO policies control access by evaluating user roles against cluster labels. The policy engine receives user and cluster context as input, then evaluates specific permission rules:
| Rego |
|---|
| # Input structure for team-based authorization
{
"user": {"roles": ["devops", "production", "observer"]},
"cluster": {"labels": {"team": "devops", "environment": "production"}}
}
|
When checking if a user can perform an operation (e.g., read_logs), the policy engine queries the corresponding rule directly (e.g., data.pdns_permissions.read_logs) using this input context.
Note: The user data structure depends on how the OIDC server provides user data.
Example: Static Users Configuration
First, let's look at the user definitions. In production, these would come from OIDC, but for this example we use static users:
| YAML |
|---|
| # Example: Team-Based REGO Authorization Policies
policy:
# Static Users Configuration
# In production, users would come from OIDC with team claims
staticUsers:
# DevOps Team Lead - Full access to DevOps team clusters
devops-lead:
id: "devops-lead"
password: "secret"
sub: "devops-lead"
name: "DevOps Team Lead"
email: "lead@devops.example.com"
roles:
- "devops" # Team membership
- "team-lead" # Leadership role
- "production" # Can access production
- "staging" # Can access staging
- "development" # Can access development
- "operator" # Can restart instances
- "observer" # Can read logs
# DevOps Developer - Limited access to non-prod
devops-developer:
id: "devops-developer"
password: "secret"
sub: "devops-developer"
name: "DevOps Developer"
email: "dev@devops.example.com"
roles:
- "devops" # Team membership
- "developer" # Developer role
- "staging" # Can access staging
- "development" # Can access development
- "observer" # Can read logs
# Note: No "production" role - cannot see prod clusters
# Note: No "operator" role - cannot restart instances
# Platform Team Member - Access to Platform team clusters only
platform-engineer:
id: "platform-engineer"
password: "secret"
sub: "platform-engineer"
name: "Platform Engineer"
email: "eng@platform.example.com"
roles:
- "platform" # Different team
- "production"
- "staging"
- "development"
- "operator"
- "observer"
# Note: Cannot see DevOps team clusters
# Global Administrator - Access to all teams
admin:
id: "admin"
password: "secret"
sub: "admin"
name: "Global Administrator"
email: "admin@example.com"
roles:
- "admin" # Admin bypass
- "global" # Global access
# REGO Authorization Policies
|
User Roles Explained
DevOps Team Lead:
- Roles: devops, team-lead, production, staging, development, operator, observer
- Can access: All DevOps team environments
- Can perform: All operations (read logs, clear cache, restart instances)
DevOps Developer:
- Roles: devops, developer, staging, development, observer
- Can access: Staging and development only (no production role)
- Can perform: Read-only operations (read logs, DNS checks - no operator role means no cache clearing or instance management)
Platform Engineer:
- Roles: platform, production, staging, development, operator, observer
- Can access: Platform team clusters only (different team)
- Cannot see: DevOps team clusters
Global Administrator:
- Roles: admin, global
- Can access: All clusters (admin bypass)
- Can perform: All operations
SPOG uses three REGO packages: pdns_permissions (operation permissions like read_logs, restart_instance_set), pdns_global_flags (UI access permissions for dashboards and navigation), and user (helper functions for team membership and environment access checks).
REGO Policy Breakdown
The policies define three packages:
1. pdns_permissions.rego - Operation Permissions
This package defines well-known operations that services check:
| Rego |
|---|
| # Basic connection - all authenticated users
connect if true
# Read cluster state - requires team membership and visibility
read if user.can_see_cluster
# Read logs - requires observer role + cluster visibility
read_logs if user.can_observe_cluster
# Clear cache - requires operator role + cluster visibility (destructive operation)
clear_cache if user.can_manage_instances
# Restart instances - requires operator role + cluster visibility
restart_instance_set if user.can_manage_instances
# Delete pods - requires operator role + cluster visibility
delete_pod if user.can_manage_instances
# DNS check - requires observer role + cluster visibility
dns_check if user.can_observe_cluster
|
Each permission references functions from the user package that evaluate access based on roles and cluster labels. The admin bypass is built into the helper functions themselves (see user.rego below).
2. pdns_global_flags.rego - Dashboard and Navigation Permissions
This package defines custom permission flags for UI access control:
| Rego |
|---|
| # DevOps team dashboard flags
dashboard_devops_overview if "devops" in input.user.roles
dashboard_devops_production if "devops" in input.user.roles
dashboard_devops_environments if "devops" in input.user.roles
# Platform team dashboard flags
dashboard_platform_overview if "platform" in input.user.roles
dashboard_platform_production if "platform" in input.user.roles
dashboard_platform_environments if "platform" in input.user.roles
# Global admin dashboard flags
dashboard_global_admin if "admin" in input.user.roles
# Navigation item access flags
navigation_devops_resources if "devops" in input.user.roles
navigation_platform_resources if "platform" in input.user.roles
# Admin has access to everything
dashboard_devops_overview if "admin" in input.user.roles
dashboard_platform_overview if "admin" in input.user.roles
navigation_devops_resources if "admin" in input.user.roles
navigation_platform_resources if "admin" in input.user.roles
|
These flags are referenced by dashboard requires fields and navigation item requires fields to control visibility. Note that this package accesses input.user.roles directly, unlike pdns_permissions.rego which uses helper functions from the user package.
3. user.rego - User Authorization Logic
This package contains the core authorization logic:
Role Convenience Flags:
| Rego |
|---|
| roles := input.user.roles
# Role Flags
admin if "admin" in roles
team_lead if "team-lead" in roles
developer if "developer" in roles
operator if "operator" in roles
observer if "observer" in roles
# Team Membership
is_devops_team_member if "devops" in roles
is_platform_team_member if "platform" in roles
|
These convenience flags simplify checking if a user has specific roles. Instead of writing "observer" in input.user.roles everywhere, we can just check observer. The roles variable is set once at the top of the package from input.user.roles.
Team-Based Cluster Visibility:
| Rego |
|---|
| # User must belong to the same team as the cluster
has_matching_team if {
some team in roles
team in input.cluster.labels.team
}
|
This rule checks if any of the user's roles matches the cluster's team label. For example:
- User roles: ["devops", "production", "observer"]
- Cluster labels: {team: "devops", environment: "production"}
- Evaluation: "devops" in roles equals "devops" in cluster labels → TRUE
Environment Access:
| Rego |
|---|
| # User must have role matching cluster environment
has_matching_environment if {
some env in input.cluster.labels.environment
env in roles
}
|
This rule checks if the cluster's environment is in the user's roles:
- User roles: ["devops", "staging", "development", "observer"]
- Cluster labels: {team: "devops", environment: "production"}
- Evaluation: "production" not in roles → FALSE (user cannot access production)
Cluster Visibility Rule:
| Rego |
|---|
| # User can see cluster if team AND environment match
can_see_cluster if {
has_matching_team
has_matching_environment
}
|
Both team and environment must match for visibility. This implements the dual-gating strategy:
1. Must be same team
2. Must have environment access
Observer Capabilities:
| Rego |
|---|
| # Can read logs and check DNS if observer role + visibility
can_observe_cluster if {
can_see_cluster
observer
}
# Admin bypass
can_observe_cluster if admin
|
Observer role grants read-only access: view logs, check DNS, read cluster state. Requires cluster visibility first. Admins have observer capabilities on all clusters.
Operator Capabilities:
| Rego |
|---|
| # Can restart instances and delete pods if operator role + visibility
can_manage_instances if {
can_see_cluster
operator
}
# Admin bypass
can_manage_instances if admin
|
Operator role grants infrastructure management: restart instances, delete pods. Requires cluster visibility first. Admins have operator capabilities on all clusters.
Complete REGO Policy Configuration
Here's the complete policy configuration with all three packages:
| YAML |
|---|
| # Example: Team-Based REGO Authorization Policies
policy:
# Static Users Configuration
# In production, users would come from OIDC with team claims
policies:
# Operation Permission Definitions
# These define well-known operations that services check
pdns_permissions.rego: |
package pdns_permissions
import data.user
# Basic connection - all authenticated users
connect if true
# Read cluster state - requires team membership and visibility
read if user.can_see_cluster
# Read logs - requires observer role + cluster visibility
read_logs if user.can_observe_cluster
# Clear DNS cache - requires operator role + cluster visibility (destructive operation)
clear_cache if user.can_manage_instances
# Restart instances - requires operator role + cluster visibility
restart_instance_set if user.can_manage_instances
# Delete pods - requires operator role + cluster visibility
delete_pod if user.can_manage_instances
# DNS check - requires observer role + cluster visibility
dns_check if user.can_observe_cluster
# Dashboard and Navigation Permission Flags
# These are custom flags for controlling UI access
pdns_global_flags.rego: |
package pdns_global_flags
# Dashboard access flags
dashboard_devops_overview if "devops" in input.user.roles
dashboard_devops_overview if "admin" in input.user.roles
dashboard_devops_production if "devops" in input.user.roles
dashboard_devops_production if "admin" in input.user.roles
dashboard_devops_environments if "devops" in input.user.roles
dashboard_devops_environments if "admin" in input.user.roles
dashboard_platform_overview if "platform" in input.user.roles
dashboard_platform_overview if "admin" in input.user.roles
dashboard_platform_production if "platform" in input.user.roles
dashboard_platform_production if "admin" in input.user.roles
dashboard_platform_environments if "platform" in input.user.roles
dashboard_platform_environments if "admin" in input.user.roles
dashboard_global_admin if "admin" in input.user.roles
# Navigation item access flags
navigation_devops_resources if "devops" in input.user.roles
navigation_devops_resources if "admin" in input.user.roles
navigation_platform_resources if "platform" in input.user.roles
navigation_platform_resources if "admin" in input.user.roles
# User Authorization Logic
# This evaluates whether a user can access specific clusters
user.rego: |
package user
roles := input.user.roles
# Role Flags
admin if "admin" in roles
team_lead if "team-lead" in roles
developer if "developer" in roles
operator if "operator" in roles
observer if "observer" in roles
# Team Membership
is_devops_team_member if "devops" in roles
is_platform_team_member if "platform" in roles
# Team-Based Cluster Visibility
# User must belong to the same team as the cluster
has_matching_team if {
some team in roles
team in input.cluster.labels.team
}
# Admin bypass - admins see all clusters regardless of team
has_matching_team if admin
# Environment Access
# User must have role matching cluster environment
has_matching_environment if {
some env in input.cluster.labels.environment
env in roles
}
# Admin bypass for environment
has_matching_environment if admin
# Cluster Visibility Rule
# User can see cluster if team AND environment match
can_see_cluster if {
has_matching_team
has_matching_environment
}
# Observer Capabilities
# Can read logs and check DNS if observer role + visibility
can_observe_cluster if {
can_see_cluster
observer
}
can_observe_cluster if admin
# Operator Capabilities
# Can restart instances and delete pods if operator role + visibility
can_manage_instances if {
can_see_cluster
operator
}
can_manage_instances if admin
|
Authorization Flow Example
Let's trace a complete authorization decision:
Scenario: DevOps Developer tries to read logs from production cluster
Input (passed to policy engine when querying data.pdns_permissions.read_logs):
| JSON |
|---|
| {
"user": {
"roles": ["devops", "developer", "staging", "development", "observer"]
},
"cluster": {
"labels": {
"team": "devops",
"environment": "production"
}
}
}
|
Evaluation:
- Check has_matching_team:
- User roles contain
"devops"
- Cluster team is
"devops"
-
Result: TRUE ✓
-
Check has_matching_environment:
- User roles are
["devops", "developer", "staging", "development", "observer"]
- Cluster environment is
"production"
"production" in roles? → FALSE
-
Result: FALSE ✗
-
Check can_see_cluster:
- Requires:
has_matching_team AND has_matching_environment
- Evaluation: TRUE AND FALSE → FALSE
-
Result: FALSE ✗
-
Check read_logs permission:
- Requires:
can_observe_cluster
can_observe_cluster requires: can_see_cluster AND observer role
- Evaluation: FALSE AND TRUE → FALSE
- Result: DENIED ✗
Outcome: DevOps Developer CANNOT read logs from production cluster because they lack the "production" role, even though they:
- Belong to the correct team
- Have the observer role
- Are authenticated
This demonstrates environment-based isolation within a team.
Another Example: DevOps Team Lead Accesses Production
Scenario: DevOps Team Lead tries to restart instance on production cluster
Input (passed to policy engine when querying data.pdns_permissions.restart_instance_set):
| JSON |
|---|
| {
"user": {
"roles": ["devops", "team-lead", "production", "staging", "development", "operator", "observer"]
},
"cluster": {
"labels": {
"team": "devops",
"environment": "production"
}
}
}
|
Evaluation:
- Check has_matching_team:
- User roles contain
"devops"
- Cluster team is
"devops"
-
Result: TRUE ✓
-
Check has_matching_environment:
- User roles contain
"production"
- Cluster environment is
"production"
-
Result: TRUE ✓
-
Check can_see_cluster:
- Requires:
has_matching_team AND has_matching_environment
- Evaluation: TRUE AND TRUE → TRUE
-
Result: TRUE ✓
-
Check can_manage_instances:
- Requires:
can_see_cluster AND operator role
- User has
operator role
- Evaluation: TRUE AND TRUE → TRUE
-
Result: TRUE ✓
-
Check restart_instance_set permission:
- Requires:
can_manage_instances OR admin
- Evaluation: TRUE
- Result: ALLOWED ✓
Outcome: DevOps Team Lead CAN restart instances on production cluster because they have:
- Correct team membership
- Production environment access
- Operator role for infrastructure operations
Integration Point: Policies Protect Dashboards and Navigation
Notice the complete integration:
- Step 1 labeled clusters with
team: "devops"
- Step 2 created dashboards with
requires: ["dashboard_devops_overview"]
- Step 3 created navigation linking to those dashboards
- Step 4 implements
dashboard_devops_overview REGO permission flag checking team membership
Result: Only users with devops role (or admin role) can:
- See "DevOps Team" navigation menu
- Access /team/devops dashboard
- View DevOps clusters in widgets
- Perform operations on DevOps clusters
This is the complete security model enforcing team-based isolation.
Deploy Steps 2-4: Glass UI with Complete Configuration
Deploy Glass UI with dashboards, navigation, and REGO policies:
| Bash |
|---|
| helm install glass-ui \
oci://registry.open-xchange.com/cc-glass/glass-ui \
--version "1.0.0" \
--namespace controlplane \
--set ui.ingress.host="$GLASS_HOSTNAME" \
--set global.imagePullSecretsList[0]=registry-credentials \
-f team-based-dashboard.yaml \
-f team-based-navigation.yaml \
-f team-based-rego.yaml
|
| Bash |
|---|
| helm install glass-ui \
oci://registry.open-xchange.com/cc-glass/glass-ui \
--version "1.0.0" \
--namespace controlplane \
--set global.imagePullSecretsList[0]=registry-credentials \
--set "ui.config.nats.serverUrl=ws://localhost:8222" \
-f team-based-dashboard.yaml \
-f team-based-navigation.yaml \
-f team-based-rego.yaml
|
Then start port-forwards:
| Bash |
|---|
| kubectl port-forward svc/glass-ui 8080:80 -n controlplane &
kubectl port-forward svc/glass-nats 8222:8080 -n controlplane &
|
| Bash |
|---|
| helm install glass-ui \
oci://registry.open-xchange.com/cc-glass/glass-ui \
--version "1.0.0" \
--namespace controlplane \
--set global.imagePullSecretsList[0]=registry-credentials \
--set ui.service.type=NodePort \
--set ui.service.nodePort=31080 \
--set "ui.config.nats.serverUrl=ws://${NODE_IP}:31222" \
-f team-based-dashboard.yaml \
-f team-based-navigation.yaml \
-f team-based-rego.yaml
|
Each values file configures one aspect of the Glass UI:
team-based-dashboard.yaml - Dashboard definitions with team-based filtering
team-based-navigation.yaml - Navigation menu structure for all teams
team-based-rego.yaml - REGO policies for authorization and static user definitions
After deployment, access Glass UI at https://$GLASS_HOSTNAME and log in with one of the configured users to see the team-based isolation in action.
After deployment, access Glass UI at http://localhost:8080 and log in with one of the configured users to see the team-based isolation in action.
After deployment, access Glass UI at http://<node-ip>:31080 and log in with one of the configured users to see the team-based isolation in action.
Login Credentials:
| Username |
Password |
Access |
devops-lead |
secret |
DevOps team, all environments, operator permissions |
devops-developer |
secret |
DevOps team, staging/dev only, read-only |
platform-engineer |
secret |
Platform team, all environments, operator permissions |
admin |
secret |
Global administrator, full access |
What You Accomplished
Step 1: Labeled Clusters
- Applied team, environment, and role labels to user plane clusters
- Created the foundation for all subsequent filtering and access control
Step 2: Created Team Dashboards
- Built dashboards filtered by team = "devops" expressions
- Configured multiple views (all clusters, production only, by environment)
- Linked dashboards to REGO permissions
Step 3: Configured Team Navigation
- Created hierarchical menu structure for team
- Linked navigation items to dashboard URLs
- Organized tools and resources for easy access
Step 4: Implemented REGO Policies
- Defined team-based cluster visibility rules
- Implemented environment-based access restrictions
- Created role-based operation permissions (observer, operator)
- Configured static users with different access levels
Try It Yourself
Now that you understand how the components work together, here are some modifications you can try to deepen your understanding.
Need Help?
If you get stuck, reference solutions are available in the Team-Based Deployment Solutions guide.
Add a New Team
Add a "security" team with their own clusters and access. You'll need to:
- Create a new cluster with security team labels
- Add a security team dashboard to your dashboard configuration
- Add a navigation menu for the security team
- Add REGO policies granting dashboard access to users with the
security role
- Add a security team user to test access
Change Dashboard Filters
Modify existing dashboards to show different cluster subsets. Try creating filters that:
- Show only recursors across all teams
- Show production clusters from multiple teams
- Exclude development environments
Add a Cross-Team Dashboard
Create a dashboard visible to multiple teams for shared infrastructure. This requires:
- A dashboard configuration with a filter showing shared resources (e.g., all authoritative servers)
- REGO rules that grant access to users from multiple teams
Restrict Operator Access by Environment
Modify the REGO policy to only allow operator actions in non-production. Consider:
- How to check the cluster's environment label
- Whether to require an additional role for production operations
- How to structure the rules for clarity
Add a New User Role
Create a "read-only admin" role that can see all clusters but cannot perform operations. Think about:
- Which team roles to include for visibility
- Which environment roles to include
- Which operation roles to omit (operator, content-manager)
Refactoring with Parameterized Routes
As your deployment grows, you may notice repetitive dashboard definitions—one for each team with nearly identical structure. SPOG supports parameterized routes that let you create generic, reusable configurations with dynamic permission checks.
Understanding Route Parameters
SPOG uses route parameters (:paramName) to create dynamic dashboards:
:paramName - For Display and Filtering
Used in dashboard URLs, titles, descriptions, and filter expressions:
- URL pattern:
/team/:team defines a route parameter named team
- When user visits
/team/devops, the :team placeholder becomes "devops"
- When user visits
/team/platform, the :team placeholder becomes "platform"
Dynamic Permission Checking
The requires field supports object format with arguments that pass route parameters to REGO policies:
| YAML |
|---|
| requires:
- permission: "see_team_dashboard"
arguments:
- name: team
value: ":team" # Passes route parameter to REGO
|
When user visits /team/devops:
- The
:team value is extracted as "devops"
- REGO policy receives
input.arguments.team = "devops"
- Policy evaluates:
input.arguments.team in input.user.roles
- User with
devops role gains access; others are denied
This means a single dashboard definition can serve all teams while maintaining proper access control through dynamic REGO evaluation.
Before: Repetitive Dashboard Definitions
The original configuration requires a separate dashboard for each team:
| YAML |
|---|
| # One dashboard per team - repetitive!
devops-overview:
title: "DevOps Team Dashboard"
url: /team/devops
graphs:
- widget: "cc-state-tree-table"
args:
filter: 'team = "devops"'
platform-overview:
title: "Platform Team Dashboard"
url: /team/platform
graphs:
- widget: "cc-state-tree-table"
args:
filter: 'team = "platform"'
# Need to add another dashboard for each new team...
|
After: Generic Dashboard with Route Parameters
With parameterized routes and dynamic permissions, one definition works for all teams:
| YAML |
|---|
| # Single dashboard serves ALL teams
team-overview:
title: ":team Team Dashboard"
url: /team/:team
requires:
- permission: "see_team_dashboard"
arguments:
- name: team
value: ":team" # Route parameter passed to REGO
graphs:
- widget: "cc-state-tree-table"
title: ":team Clusters"
args:
filter: 'team = ":team"'
- widget: "cc-state-readiness-heatmap"
title: "Cluster Health"
args:
filter: 'team = ":team"'
|
Now:
- /team/devops shows "devops Team Dashboard" with filter team = "devops" and REGO receives input.arguments.team = "devops"
- /team/platform shows "platform Team Dashboard" with filter team = "platform" and REGO receives input.arguments.team = "platform"
- /team/security shows "security Team Dashboard" with filter team = "security" and REGO receives input.arguments.team = "security"
Adding a new team requires only adding navigation links and assigning the team role to users.
Refactored Navigation
Navigation items link to the parameterized URLs:
| YAML |
|---|
| navigation:
menus:
- name: "DevOps Team"
sections:
- name: "Dashboards"
items:
- name: "Team Overview"
url: "/team/devops" # Fills :team with "devops"
- name: "Production"
url: "/team/devops/production"
- name: "Platform Team"
sections:
- name: "Dashboards"
items:
- name: "Team Overview"
url: "/team/platform" # Fills :team with "platform"
- name: "Production"
url: "/team/platform/production"
|
Refactored REGO Policies
With dynamic permission arguments, one REGO rule handles all teams. The input.arguments object receives the route parameter value:
| YAML |
|---|
| # Dashboard passes route parameter as argument
team-overview:
requires:
- permission: "see_team_dashboard"
arguments:
- name: team
value: ":team" # For /team/devops, REGO receives input.arguments.team = "devops"
|
| Rego |
|---|
| # Single rule handles ALL teams dynamically
see_team_dashboard if {
input.arguments.team in input.user.roles
}
see_team_dashboard if "admin" in input.user.roles
# For multi-argument scenarios (team + tier)
see_team_tier_dashboard if {
input.arguments.team in input.user.roles
input.arguments.tier in input.user.roles
}
see_team_tier_dashboard if "admin" in input.user.roles
|
How it works:
- User visits
/team/devops
- Dashboard config passes
arguments: [{name: "team", value: ":team"}]
- UI extracts
:team as "devops" and sends to policy engine: {arguments: {team: "devops"}}
- REGO evaluates:
"devops" in input.user.roles
- User with
devops role → access granted; user with platform role → access denied
This eliminates team-specific REGO rules entirely—one rule handles unlimited teams.
Benefits of Parameterized Routes
| Aspect |
Before (Hardcoded) |
After (Parameterized) |
| Adding a team |
Add dashboard + navigation + REGO |
Add navigation link only |
| Dashboard count |
One per team (N dashboards) |
One generic (1 dashboard) |
| REGO rules |
One rule per team |
One rule for all teams |
| Maintenance |
Update each dashboard separately |
Update once, applies to all |
| Consistency |
Risk of drift between teams |
Guaranteed identical structure |
| Permission security |
Per-dashboard requires |
Dynamic via input.arguments |
No Per-Team REGO Rules
With dynamic permission arguments, one REGO rule handles all teams. The rule see_team_dashboard if { input.arguments.team in input.user.roles } automatically works for any team—DevOps, Platform, Security, or any team you add in the future. Just assign the team role to users and add navigation links.
Refactored Dashboard Configuration
| YAML |
|---|
| # Example: Team-Based Dashboard Configuration with Parameterized Routes
#
# This example demonstrates how to use route parameters to create
# generic, reusable dashboard configurations with dynamic permission checking.
#
# Benefits:
# - Single dashboard definition serves all teams
# - Add new teams without changing dashboard OR REGO config
# - Cleaner, more maintainable configuration
# - Dynamic permission checking via input.arguments
#
# How it works:
# - URLs like /team/:team contain route parameters
# - :team in titles and filters is replaced with the route parameter value
# - The requires field passes arguments to REGO for dynamic evaluation
# - Example: /team/devops -> REGO receives input.arguments.team = "devops"
globalConfig:
dashboards:
# Generic team dashboard - works for ANY team
# Permission uses arguments - e.g., /team/devops passes team="devops" to REGO
team-overview:
title: ":team Team Dashboard"
description: "All :team team PowerDNS clusters"
url: /team/:team
requires:
- permission: "see_team_dashboard"
arguments:
- name: team
value: ":team" # Route parameter passed to REGO
graphs:
# Show all clusters for this team
- widget: "cc-state-tree-table"
title: ":team Clusters"
args:
filter: 'team = ":team"'
# Health heatmap for this team
- widget: "cc-state-readiness-heatmap"
title: "Cluster Health"
args:
filter: 'team = ":team"'
# Generic production view - works for ANY team
team-production:
title: ":team Production"
description: "Production clusters for :team team"
url: /team/:team/production
requires:
- permission: "see_team_tier_dashboard"
arguments:
- name: team
value: ":team"
- name: tier
value: "production" # Static value
graphs:
- widget: "cc-state-tree-table"
title: "Production Clusters"
args:
filter: 'team = ":team" and environment = "production"'
- widget: "cc-state-readiness-pie-charts"
title: "Production Readiness Distribution"
args:
filter: 'team = ":team" and environment = "production"'
# Generic environment view - works for ANY team
team-environments:
title: ":team Environments"
description: "All environments for :team team"
url: /team/:team/environments
requires:
- permission: "see_team_dashboard"
arguments:
- name: team
value: ":team"
graphs:
- widget: "cc-state-tree-table"
title: "Development"
args:
filter: 'team = ":team" and environment = "development"'
- widget: "cc-state-tree-table"
title: "Staging"
args:
filter: 'team = ":team" and environment = "staging"'
- widget: "cc-state-tree-table"
title: "Production"
args:
filter: 'team = ":team" and environment = "production"'
# Comparison: Before vs After Parameterized Routes
# ================================================
#
# BEFORE (hardcoded - one dashboard per team, one REGO rule per team):
# --------------------------------------------------------------------
# devops-overview:
# title: "DevOps Team Dashboard"
# url: /team/devops
# requires:
# - "dashboard_devops_overview" # String format
# filter: 'team = "devops"'
#
# platform-overview:
# title: "Platform Team Dashboard"
# url: /team/platform
# requires:
# - "dashboard_platform_overview" # Need separate REGO rule!
# filter: 'team = "platform"'
#
# AFTER (parameterized - one dashboard for all teams, one REGO rule):
# -------------------------------------------------------------------
# team-overview:
# title: ":team Team Dashboard"
# url: /team/:team
# requires:
# - permission: "see_team_dashboard"
# arguments:
# - name: team
# value: ":team" # Dynamic argument
# filter: 'team = ":team"'
#
# Works for ALL teams - just add navigation links!
# /team/devops -> REGO receives input.arguments.team = "devops"
# /team/platform -> REGO receives input.arguments.team = "platform"
# /team/security -> REGO receives input.arguments.team = "security"
|
Refactored Navigation Configuration
| YAML |
|---|
| # Example: Team-Based Navigation Configuration with Placeholders
#
# Navigation links point to parameterized dashboard URLs.
# When a user clicks "/team/devops", the :team placeholder in the
# dashboard definition is filled with "devops".
#
# Adding a new team only requires:
# 1. Add a new menu section here with links to /team/<new-team>
# 2. Add REGO permissions for the new team
# No dashboard changes needed!
globalConfig:
navigation:
menus:
# DevOps Team Menu - links to /team/devops (fills :team with "devops")
- name: "DevOps Team"
sections:
- name: "Dashboards"
items:
- name: "Team Overview"
url: "/team/devops"
description: "All DevOps clusters"
- name: "Production"
url: "/team/devops/production"
description: "Production clusters only"
- name: "By Environment"
url: "/team/devops/environments"
description: "Dev, Staging, Prod views"
# External Links (EXAMPLE ONLY - these URLs are fictional)
- name: "Resources"
items:
- name: "Team Runbook"
url: "https://docs.example.com/devops/runbook"
description: "DevOps operational procedures"
external: true
requires:
- "navigation_devops_resources"
- name: "Team Wiki"
url: "https://wiki.example.com/devops"
description: "DevOps team wiki"
external: true
requires:
- "navigation_devops_resources"
# Platform Team Menu - links to /team/platform (fills :team with "platform")
- name: "Platform Team"
sections:
- name: "Dashboards"
items:
- name: "Team Overview"
url: "/team/platform"
description: "All Platform clusters"
- name: "Production"
url: "/team/platform/production"
description: "Production clusters only"
- name: "By Environment"
url: "/team/platform/environments"
description: "Dev, Staging, Prod views"
# External Links (EXAMPLE ONLY - these URLs are fictional)
- name: "Resources"
items:
- name: "Team Runbook"
url: "https://docs.example.com/platform/runbook"
description: "Platform operational procedures"
external: true
requires:
- "navigation_platform_resources"
- name: "Team Wiki"
url: "https://wiki.example.com/platform"
description: "Platform team wiki"
external: true
requires:
- "navigation_platform_resources"
# Operations Menu (shared across teams)
- name: "Operations"
sections:
- name: "DNS Operations"
items:
- name: "DNS Check"
url: "/dns-query"
- name: "Cache Management"
url: "/clear-cache/all"
# Adding a New Team
# =================
#
# To add a "Security" team, just add this menu section:
#
# - name: "Security Team"
# sections:
# - name: "Dashboards"
# items:
# - name: "Team Overview"
# url: "/team/security"
# - name: "Production"
# url: "/team/security/production"
# - name: "By Environment"
# url: "/team/security/environments"
#
# The existing placeholder dashboards will automatically work for the new team.
# You only need to add REGO permissions (see team-based-placeholder-rego.yaml).
|
Refactored REGO Configuration
| YAML |
|---|
| # Example: Team-Based REGO Authorization Policies with Dynamic Arguments
#
# With dynamic permission arguments, one REGO rule handles all teams.
# The input.arguments object receives values from dashboard requires fields,
# enabling truly dynamic access control without per-team rules.
#
# How it works:
# - Dashboard config passes arguments: [{name: "team", value: ":team"}]
# - UI extracts route parameter and sends to policy engine
# - REGO evaluates: input.arguments.team in input.user.roles
# - User with matching team role gains access
policy:
# Static Users Configuration
# In production, users would come from OIDC with team claims
staticUsers:
# DevOps Team Lead - Full access to DevOps team clusters
devops-lead:
id: "devops-lead"
password: "secret"
sub: "devops-lead"
name: "DevOps Team Lead"
email: "lead@devops.example.com"
roles:
- "devops" # Team membership
- "team-lead" # Leadership role
- "production" # Can access production
- "staging" # Can access staging
- "development" # Can access development
- "operator" # Can restart instances
- "observer" # Can read logs
# DevOps Developer - Limited access to non-prod
devops-developer:
id: "devops-developer"
password: "secret"
sub: "devops-developer"
name: "DevOps Developer"
email: "dev@devops.example.com"
roles:
- "devops" # Team membership
- "developer" # Developer role
- "staging" # Can access staging
- "development" # Can access development
- "observer" # Can read logs
# Note: No "production" role - cannot see prod clusters
# Note: No "operator" role - cannot restart instances
# Platform Team Member - Access to Platform team clusters only
platform-engineer:
id: "platform-engineer"
password: "secret"
sub: "platform-engineer"
name: "Platform Engineer"
email: "eng@platform.example.com"
roles:
- "platform" # Different team
- "production"
- "staging"
- "development"
- "operator"
- "observer"
# Note: Cannot see DevOps team clusters
# Global Administrator - Access to all teams
admin:
id: "admin"
password: "secret"
sub: "admin"
name: "Global Administrator"
email: "admin@example.com"
roles:
- "admin" # Admin bypass
- "global" # Global access
# REGO Authorization Policies
policies:
# Operation Permission Definitions
# These define well-known operations that services check
pdns_permissions.rego: |
package pdns_permissions
import data.user
# Basic connection - all authenticated users
connect if true
# Read cluster state - requires team membership and visibility
read if user.can_see_cluster
# Read logs - requires observer role + cluster visibility
read_logs if user.can_observe_cluster
# Clear DNS cache - requires operator role + cluster visibility (destructive operation)
clear_cache if user.can_manage_instances
# Restart instances - requires operator role + cluster visibility
restart_instance_set if user.can_manage_instances
# Delete pods - requires operator role + cluster visibility
delete_pod if user.can_manage_instances
# DNS check - requires observer role + cluster visibility
dns_check if user.can_observe_cluster
# Dashboard and Navigation Permission Flags
# Dynamic permission checking using input.arguments
pdns_global_flags.rego: |
package pdns_global_flags
# =============================================================================
# DYNAMIC PERMISSION FLAGS (using input.arguments)
# =============================================================================
# Dynamic team dashboard access
# Uses input.arguments.team passed from the UI based on route parameters
# Example: requires: [{ permission: "see_team_dashboard", arguments: [{ name: "team", value: ":team" }] }]
see_team_dashboard if {
input.arguments.team in input.user.roles
}
see_team_dashboard if "admin" in input.user.roles
# Dynamic team and tier dashboard access
# Uses multiple arguments from route parameters or static values
# Example: requires: [{ permission: "see_team_tier_dashboard", arguments: [{ name: "team", value: ":team" }, { name: "tier", value: "production" }] }]
see_team_tier_dashboard if {
input.arguments.team in input.user.roles
input.arguments.tier in input.user.roles
}
see_team_tier_dashboard if "admin" in input.user.roles
# =============================================================================
# STATIC PERMISSION FLAGS (for non-parameterized routes)
# =============================================================================
# Global overview - accessible to all authenticated users
dashboard_global_overview if {
not "machine" in input.user.roles
not input.robot
}
# Navigation item access flags
navigation_devops_resources if "devops" in input.user.roles
navigation_devops_resources if "admin" in input.user.roles
navigation_platform_resources if "platform" in input.user.roles
navigation_platform_resources if "admin" in input.user.roles
# User Authorization Logic
# This evaluates whether a user can access specific clusters
user.rego: |
package user
roles := input.user.roles
# Role Flags
admin if "admin" in roles
team_lead if "team-lead" in roles
developer if "developer" in roles
operator if "operator" in roles
observer if "observer" in roles
# Team Membership
is_devops_team_member if "devops" in roles
is_platform_team_member if "platform" in roles
# Team-Based Cluster Visibility
# User must belong to the same team as the cluster
has_matching_team if {
some team in roles
team in input.cluster.labels.team
}
# Admin bypass - admins see all clusters regardless of team
has_matching_team if admin
# Environment Access
# User must have role matching cluster environment
has_matching_environment if {
some env in input.cluster.labels.environment
env in roles
}
# Admin bypass for environment
has_matching_environment if admin
# Cluster Visibility Rule
# User can see cluster if team AND environment match
can_see_cluster if {
has_matching_team
has_matching_environment
}
# Observer Capabilities
# Can read logs and check DNS if observer role + visibility
can_observe_cluster if {
can_see_cluster
observer
}
can_observe_cluster if admin
# Operator Capabilities
# Can restart instances and delete pods if operator role + visibility
can_manage_instances if {
can_see_cluster
operator
}
can_manage_instances if admin
# Adding a New Team
# =================
#
# With dynamic permissions, adding a new team is simple:
#
# 1. Assign the team role to users (e.g., "security" role)
# 2. Add navigation links pointing to /team/security
#
# That's it! No REGO changes needed.
#
# The see_team_dashboard rule automatically works:
# - User visits /team/security
# - Dashboard passes arguments: [{name: "team", value: ":team"}]
# - REGO receives input.arguments.team = "security"
# - Rule evaluates: "security" in input.user.roles
# - User with "security" role gains access
|
Complete Configuration Reference
The complete team-based configuration is split across three files for maintainability. Each file handles one aspect of the Glass UI configuration:
Dashboard Configuration
| YAML |
|---|
| # Example: Team-Based Dashboard Configuration
globalConfig:
dashboards:
# Dashboard 1: DevOps Team Overview
# Main dashboard showing all DevOps team clusters
devops-overview:
title: "DevOps Team Dashboard"
description: "PowerDNS clusters managed by the DevOps team"
url: /team/devops
requires:
- "dashboard_devops_overview" # REGO permission flag
graphs:
# Widget 1: Tree table showing all DevOps clusters
- widget: "cc-state-tree-table"
title: "DevOps Cluster State"
args:
# Filter: Only show clusters with team="devops" label
filter: 'team = "devops"'
# Widget 2: Heatmap showing cluster readiness
- widget: "cc-state-readiness-heatmap"
title: "DevOps Cluster Health"
args:
filter: 'team = "devops"'
# Dashboard 2: DevOps Production View
# Filtered view showing only production clusters
devops-production:
title: "DevOps Production"
description: "Production PowerDNS clusters for DevOps team"
url: /team/devops/production
requires:
- "dashboard_devops_production"
graphs:
- widget: "cc-state-tree-table"
title: "Production Clusters"
args:
# Multiple conditions: team AND environment
filter: 'team = "devops" and environment = "production"'
- widget: "cc-state-readiness-pie-charts"
title: "Production Readiness Distribution"
args:
filter: 'team = "devops" and environment = "production"'
# Dashboard 3: DevOps by Environment
# Separate view for each environment (dev, staging, prod)
devops-by-environment:
title: "DevOps Environments"
description: "DevOps clusters organized by environment"
url: /team/devops/environments
requires:
- "dashboard_devops_environments"
graphs:
# Development clusters
- widget: "cc-state-tree-table"
title: "Development"
args:
filter: 'team = "devops" and environment = "development"'
# Staging clusters
- widget: "cc-state-tree-table"
title: "Staging"
args:
filter: 'team = "devops" and environment = "staging"'
# Production clusters
- widget: "cc-state-tree-table"
title: "Production"
args:
filter: 'team = "devops" and environment = "production"'
# Dashboard 4: Platform Team Overview
# Main dashboard showing all Platform team clusters
platform-overview:
title: "Platform Team Dashboard"
description: "PowerDNS clusters managed by the Platform team"
url: /team/platform
requires:
- "dashboard_platform_overview" # REGO permission flag
graphs:
# Widget 1: Tree table showing all Platform clusters
- widget: "cc-state-tree-table"
title: "Platform Cluster State"
args:
filter: 'team = "platform"'
# Widget 2: Heatmap showing cluster readiness
- widget: "cc-state-readiness-heatmap"
title: "Platform Cluster Health"
args:
filter: 'team = "platform"'
# Dashboard 5: Platform Production View
# Filtered view showing only production clusters
platform-production:
title: "Platform Production"
description: "Production PowerDNS clusters for Platform team"
url: /team/platform/production
requires:
- "dashboard_platform_production"
graphs:
- widget: "cc-state-tree-table"
title: "Production Clusters"
args:
filter: 'team = "platform" and environment = "production"'
- widget: "cc-state-readiness-pie-charts"
title: "Production Readiness Distribution"
args:
filter: 'team = "platform" and environment = "production"'
# Dashboard 6: Platform by Environment
# Separate view for each environment (dev, staging, prod)
platform-by-environment:
title: "Platform Environments"
description: "Platform clusters organized by environment"
url: /team/platform/environments
requires:
- "dashboard_platform_environments"
graphs:
# Development clusters
- widget: "cc-state-tree-table"
title: "Development"
args:
filter: 'team = "platform" and environment = "development"'
# Staging clusters
- widget: "cc-state-tree-table"
title: "Staging"
args:
filter: 'team = "platform" and environment = "staging"'
# Production clusters
- widget: "cc-state-tree-table"
title: "Production"
args:
filter: 'team = "platform" and environment = "production"'
# Dashboard 7: Global Overview (Admin Only)
# Shows all clusters across all teams
global-overview:
title: "Global Cluster Overview"
description: "All PowerDNS clusters across all teams"
url: /global/all-clusters
requires:
- "dashboard_global_admin" # Only admins can see all clusters
graphs:
- widget: "cc-state-tree-table"
title: "All Clusters"
args:
filter: '' # No filter - show everything
- widget: "cc-state-readiness-heatmap"
title: "Global Cluster Health"
args:
filter: ''
# Dashboard 8: Global by Team (Admin Only)
# Shows separate widgets for each team
global-by-team:
title: "Global View by Team"
description: "All teams and their clusters"
url: /global/by-team
requires:
- "dashboard_global_admin"
graphs:
# DevOps team clusters
- widget: "cc-state-tree-table"
title: "DevOps Team"
args:
filter: 'team = "devops"'
# Platform team clusters
- widget: "cc-state-tree-table"
title: "Platform Team"
args:
filter: 'team = "platform"'
# Readiness summary across all teams
- widget: "cc-state-readiness-pie-charts"
title: "Overall Readiness by Team"
args:
filter: ''
|
Navigation Configuration
| YAML |
|---|
| # Example: Team-Based Navigation Configuration
# This example shows how to create a custom navigation menu for a specific team.
#
# The DevOps team gets a tailored menu structure focused on their workflows.
globalConfig:
navigation:
menus:
# Menu 1: DevOps Team Menu
- name: "DevOps Team"
sections:
# Section 1: Dashboard Links
- name: "Dashboards"
items:
# Link to main team dashboard
- name: "Team Overview"
url: "/team/devops"
description: "All DevOps clusters"
# Link to production-only view
- name: "Production"
url: "/team/devops/production"
description: "Production clusters only"
# Link to environment breakdown
- name: "By Environment"
url: "/team/devops/environments"
description: "Dev, Staging, Prod views"
# Section 2: External Links (EXAMPLE ONLY - these URLs are fictional)
- name: "Resources"
items:
# Example: Link to team runbook
- name: "Team Runbook"
url: "https://docs.example.com/devops/runbook"
description: "DevOps operational procedures"
external: true
requires:
- "navigation_devops_resources"
# Example: Link to team documentation
- name: "Team Wiki"
url: "https://wiki.example.com/devops"
description: "DevOps team wiki"
external: true
requires:
- "navigation_devops_resources"
# Menu 2: Platform Team Menu
- name: "Platform Team"
sections:
# Section 1: Dashboard Links
- name: "Dashboards"
items:
# Link to main team dashboard
- name: "Team Overview"
url: "/team/platform"
description: "All Platform clusters"
# Link to production-only view
- name: "Production"
url: "/team/platform/production"
description: "Production clusters only"
# Link to environment breakdown
- name: "By Environment"
url: "/team/platform/environments"
description: "Dev, Staging, Prod views"
# Section 2: External Links (EXAMPLE ONLY - these URLs are fictional)
- name: "Resources"
items:
# Example: Link to team runbook
- name: "Team Runbook"
url: "https://docs.example.com/platform/runbook"
description: "Platform operational procedures"
external: true
requires:
- "navigation_platform_resources"
# Example: Link to team documentation
- name: "Team Wiki"
url: "https://wiki.example.com/platform"
description: "Platform team wiki"
external: true
requires:
- "navigation_platform_resources"
# Menu 3: Global Admin Menu
- name: "Global Admin"
sections:
# Section 1: Global Dashboard Links
- name: "Dashboards"
items:
# Link to global overview dashboard
- name: "Global Overview"
url: "/global/all-clusters"
description: "All clusters across all teams"
# Link to by-team view
- name: "View by Team"
url: "/global/by-team"
description: "Clusters organized by team"
# Section 2: All Teams Quick Access
- name: "Team Dashboards"
items:
- name: "DevOps Team"
url: "/team/devops"
description: "DevOps team dashboard"
- name: "Platform Team"
url: "/team/platform"
description: "Platform team dashboard"
# Note: The default "Tools" menu (DNS Query, Cache Management) is automatically
# appended after these custom menus.
# Navigation Visibility:
# - Navigation menus can be conditionally displayed based on user permissions
# - REGO policies control which menus and items a user sees
# - Users only see navigation items they have permission to access
#
# Integration with Dashboards:
# - Menu items link to dashboard URLs defined in team-based-dashboard.yaml
# - Example: "/team/devops" links to devops-overview dashboard
|
REGO Policy Configuration
| YAML |
|---|
| # Example: Team-Based REGO Authorization Policies
# This example demonstrates access control policies for team-based deployments.
#
# Access Model: Users can only see and manage clusters belonging to their team
policy:
# Static Users Configuration
# In production, users would come from OIDC with team claims
staticUsers:
# DevOps Team Lead - Full access to DevOps team clusters
devops-lead:
id: "devops-lead"
password: "secret"
sub: "devops-lead"
name: "DevOps Team Lead"
email: "lead@devops.example.com"
roles:
- "devops" # Team membership
- "team-lead" # Leadership role
- "production" # Can access production
- "staging" # Can access staging
- "development" # Can access development
- "operator" # Can restart instances
- "observer" # Can read logs
# DevOps Developer - Limited access to non-prod
devops-developer:
id: "devops-developer"
password: "secret"
sub: "devops-developer"
name: "DevOps Developer"
email: "dev@devops.example.com"
roles:
- "devops" # Team membership
- "developer" # Developer role
- "staging" # Can access staging
- "development" # Can access development
- "observer" # Can read logs
# Note: No "production" role - cannot see prod clusters
# Note: No "operator" role - cannot restart instances
# Platform Team Member - Access to Platform team clusters only
platform-engineer:
id: "platform-engineer"
password: "secret"
sub: "platform-engineer"
name: "Platform Engineer"
email: "eng@platform.example.com"
roles:
- "platform" # Different team
- "production"
- "staging"
- "development"
- "operator"
- "observer"
# Note: Cannot see DevOps team clusters
# Global Administrator - Access to all teams
admin:
id: "admin"
password: "secret"
sub: "admin"
name: "Global Administrator"
email: "admin@example.com"
roles:
- "admin" # Admin bypass
- "global" # Global access
# REGO Authorization Policies
policies:
# Operation Permission Definitions
# These define well-known operations that services check
pdns_permissions.rego: |
package pdns_permissions
import data.user
# Basic connection - all authenticated users
connect if true
# Read cluster state - requires team membership and visibility
read if user.can_see_cluster
# Read logs - requires observer role + cluster visibility
read_logs if user.can_observe_cluster
# Clear DNS cache - requires operator role + cluster visibility (destructive operation)
clear_cache if user.can_manage_instances
# Restart instances - requires operator role + cluster visibility
restart_instance_set if user.can_manage_instances
# Delete pods - requires operator role + cluster visibility
delete_pod if user.can_manage_instances
# DNS check - requires observer role + cluster visibility
dns_check if user.can_observe_cluster
# Dashboard and Navigation Permission Flags
# These are custom flags for controlling UI access
pdns_global_flags.rego: |
package pdns_global_flags
# Dashboard access flags
dashboard_devops_overview if "devops" in input.user.roles
dashboard_devops_overview if "admin" in input.user.roles
dashboard_devops_production if "devops" in input.user.roles
dashboard_devops_production if "admin" in input.user.roles
dashboard_devops_environments if "devops" in input.user.roles
dashboard_devops_environments if "admin" in input.user.roles
dashboard_platform_overview if "platform" in input.user.roles
dashboard_platform_overview if "admin" in input.user.roles
dashboard_platform_production if "platform" in input.user.roles
dashboard_platform_production if "admin" in input.user.roles
dashboard_platform_environments if "platform" in input.user.roles
dashboard_platform_environments if "admin" in input.user.roles
dashboard_global_admin if "admin" in input.user.roles
# Navigation item access flags
navigation_devops_resources if "devops" in input.user.roles
navigation_devops_resources if "admin" in input.user.roles
navigation_platform_resources if "platform" in input.user.roles
navigation_platform_resources if "admin" in input.user.roles
# User Authorization Logic
# This evaluates whether a user can access specific clusters
user.rego: |
package user
roles := input.user.roles
# Role Flags
admin if "admin" in roles
team_lead if "team-lead" in roles
developer if "developer" in roles
operator if "operator" in roles
observer if "observer" in roles
# Team Membership
is_devops_team_member if "devops" in roles
is_platform_team_member if "platform" in roles
# Team-Based Cluster Visibility
# User must belong to the same team as the cluster
has_matching_team if {
some team in roles
team in input.cluster.labels.team
}
# Admin bypass - admins see all clusters regardless of team
has_matching_team if admin
# Environment Access
# User must have role matching cluster environment
has_matching_environment if {
some env in input.cluster.labels.environment
env in roles
}
# Admin bypass for environment
has_matching_environment if admin
# Cluster Visibility Rule
# User can see cluster if team AND environment match
can_see_cluster if {
has_matching_team
has_matching_environment
}
# Observer Capabilities
# Can read logs and check DNS if observer role + visibility
can_observe_cluster if {
can_see_cluster
observer
}
can_observe_cluster if admin
# Operator Capabilities
# Can restart instances and delete pods if operator role + visibility
can_manage_instances if {
can_see_cluster
operator
}
can_manage_instances if admin
|
Cleanup
To remove the team-based deployment:
| Bash |
|---|
| # Uninstall Glass UI
helm uninstall glass-ui -n controlplane
# Uninstall Glass Instrumentation from each cluster
helm uninstall glass-instrumentation -n devops-prod
helm uninstall glass-instrumentation -n devops-staging
helm uninstall glass-instrumentation -n devops-dev
helm uninstall glass-instrumentation -n platform-prod
# Uninstall PowerDNS clusters
helm uninstall devops-prod -n devops-prod
helm uninstall devops-staging -n devops-staging
helm uninstall devops-dev -n devops-dev
helm uninstall platform-prod -n platform-prod
# Uninstall Controlplane
helm uninstall team-controlplane -n controlplane
# Delete namespaces
kubectl delete namespace controlplane devops-prod devops-staging devops-dev platform-prod
# Uninstall PowerDNS CRDs
helm uninstall powerdns-crds
|