Cross-Domain Identity Federation, AuthZ/AuthN Architecture & Identity Propagation Models: Best Practices¶
Objective: Establish comprehensive identity federation architecture that unifies authentication and authorization across Rancher, RKE2 clusters, FastAPI/NiceGUI services, Postgres/FDWs, MLflow, object stores, and multi-environment deployments. When you need unified identity, when you want identity propagation, when you need least-privilege governance—this guide provides the complete framework.
Introduction¶
Identity federation is the foundation of secure, coherent distributed systems. Without unified identity architecture, systems fragment, access control drifts, and security posture degrades. This guide establishes patterns for cross-domain identity federation, authentication, authorization, and identity propagation across all system layers.
What This Guide Covers: - Architecture for identity propagation across Rancher → RKE2 clusters, FastAPI/NiceGUI services, Postgres/FDWs, MLflow, MinIO, object layers - On-prem → cloud → air-gapped identity federation - OIDC/OAuth2 patterns - ABAC vs RBAC vs ReBAC comparison - Least-privilege governance - Token management and delegation - Identity consistency enforcement - Multi-environment identity strategies
Prerequisites: - Understanding of authentication and authorization patterns - Familiarity with OIDC, OAuth2, and identity federation - Experience with multi-domain identity management
Related Documents: This document integrates with: - Identity & Access Management, RBAC/ABAC, and Least-Privilege Governance - IAM patterns - Secure-by-Design Lifecycle Architecture Across Polyglot Systems - Security lifecycle - Secure Computes, Sandboxing, and Multi-Tenant Isolation for Polyglot Systems - Isolation patterns - Operational Risk Modeling, Blast Radius Reduction & Failure Domain Architecture - Risk-aware identity
The Philosophy of Identity Federation¶
Identity Principles¶
Principle 1: Single Source of Truth - Central identity provider - Consistent identity across domains - Unified identity model
Principle 2: Least Privilege - Minimal required access - Just-in-time elevation - Regular access reviews
Principle 3: Secure Propagation - Encrypted identity tokens - Short-lived credentials - Audit all access
Identity Federation Architecture¶
Central Identity Provider¶
Architecture Pattern:
graph TB
subgraph IdP["Identity Provider"]
OIDC["OIDC Provider"]
LDAP["LDAP/AD"]
SAML["SAML"]
end
subgraph Rancher["Rancher"]
RancherAuth["Rancher Auth"]
end
subgraph RKE2["RKE2 Clusters"]
K8sRBAC["K8s RBAC"]
end
subgraph Services["Services"]
FastAPI["FastAPI"]
NiceGUI["NiceGUI"]
end
subgraph Data["Data Layer"]
Postgres["Postgres"]
FDW["FDWs"]
end
subgraph ML["ML Layer"]
MLflow["MLflow"]
MinIO["MinIO"]
end
IdP --> Rancher
Rancher --> RKE2
RKE2 --> Services
Services --> Data
Services --> ML
style IdP fill:#ffebee
style Rancher fill:#e1f5ff
style RKE2 fill:#fff4e1
style Services fill:#e8f5e9
style Data fill:#f3e5f5
style ML fill:#e0f2f1 Identity Propagation Flow¶
Flow Diagram:
sequenceDiagram
participant User
participant IdP
participant Rancher
participant RKE2
participant Service
participant Postgres
User->>IdP: Authenticate
IdP->>User: ID Token + Access Token
User->>Rancher: Present Token
Rancher->>IdP: Validate Token
IdP->>Rancher: Token Valid + Claims
Rancher->>RKE2: Propagate Identity
RKE2->>Service: Service Account Token
Service->>Postgres: DB Credentials
Postgres->>Service: Authorized Access Rancher → RKE2 Identity Propagation¶
Rancher Authentication¶
Configuration:
# Rancher OIDC configuration
rancher:
auth:
provider: "oidc"
oidc:
client_id: "rancher-client"
client_secret: "secret"
issuer: "https://idp.example.com"
scopes: ["openid", "profile", "email", "groups"]
group_claim: "groups"
user_claim: "email"
RKE2 Cluster Identity¶
K8s RBAC Mapping:
# RKE2 RBAC mapping
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: oidc-group-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: developer
subjects:
- kind: Group
name: "developers"
apiGroup: rbac.authorization.k8s.io
FastAPI/NiceGUI Identity Integration¶
FastAPI OIDC Integration¶
Pattern:
# FastAPI OIDC integration
from fastapi import Depends, HTTPException, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import jwt, JWTError
import httpx
security = HTTPBearer()
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Security(security)
) -> dict:
"""Get current user from OIDC token"""
token = credentials.credentials
# Validate token with IdP
async with httpx.AsyncClient() as client:
response = await client.get(
"https://idp.example.com/.well-known/openid-configuration"
)
jwks_uri = response.json()["jwks_uri"]
# Get JWKS
jwks_response = await client.get(jwks_uri)
jwks = jwks_response.json()
# Verify token
try:
payload = jwt.decode(
token,
jwks,
algorithms=["RS256"],
audience="api-client"
)
return payload
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/protected")
async def protected_route(user: dict = Depends(get_current_user)):
"""Protected route with identity"""
return {"user": user["email"], "groups": user.get("groups", [])}
NiceGUI Identity¶
Pattern:
# NiceGUI identity integration
from nicegui import ui
from fastapi import Depends
@ui.page("/dashboard")
async def dashboard(user: dict = Depends(get_current_user)):
"""NiceGUI page with identity"""
ui.label(f"Welcome, {user['email']}")
# Role-based UI
if "admin" in user.get("groups", []):
ui.button("Admin Panel", on_click=show_admin)
Postgres/FDW Identity¶
Postgres Role Mapping¶
Pattern:
-- Postgres role mapping from OIDC
CREATE FUNCTION map_oidc_to_postgres_role(
oidc_email TEXT,
oidc_groups TEXT[]
) RETURNS TEXT AS $$
DECLARE
pg_role TEXT;
BEGIN
-- Map OIDC groups to Postgres roles
IF 'developers' = ANY(oidc_groups) THEN
pg_role := 'app_developer';
ELSIF 'analysts' = ANY(oidc_groups) THEN
pg_role := 'analyst_role';
ELSIF 'admins' = ANY(oidc_groups) THEN
pg_role := 'admin_role';
ELSE
pg_role := 'readonly_role';
END IF;
RETURN pg_role;
END;
$$ LANGUAGE plpgsql;
FDW Identity Propagation¶
Pattern:
-- FDW identity propagation
CREATE SERVER remote_db
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (
host 'remote-host',
port '5432',
identity_propagation 'true'
);
-- User mapping with identity propagation
CREATE USER MAPPING FOR current_user
SERVER remote_db
OPTIONS (
user 'propagated_user',
identity_propagation 'true'
);
MLflow/MinIO Identity¶
MLflow Identity¶
Configuration:
# MLflow identity integration
import mlflow
from mlflow.tracking import MlflowClient
# Configure MLflow with OIDC
mlflow.set_tracking_uri("https://mlflow.example.com")
mlflow.set_experiment("my-experiment")
# Identity-aware client
client = MlflowClient(
tracking_uri="https://mlflow.example.com",
identity_token=get_oidc_token()
)
MinIO Identity¶
Configuration:
# MinIO identity configuration
minio:
identity:
provider: "oidc"
oidc:
client_id: "minio-client"
issuer: "https://idp.example.com"
scopes: ["openid", "profile"]
policies:
- name: "developer-policy"
groups: ["developers"]
permissions: ["read", "write"]
Multi-Environment Identity¶
On-Prem Identity¶
Pattern:
# On-prem identity
on_prem_identity:
provider: "ldap"
ldap:
server: "ldap://ldap.example.com"
base_dn: "dc=example,dc=com"
user_dn: "cn=users,dc=example,dc=com"
group_dn: "cn=groups,dc=example,dc=com"
Cloud Identity¶
Pattern:
# Cloud identity
cloud_identity:
provider: "oidc"
oidc:
issuer: "https://accounts.google.com"
client_id: "google-client"
scopes: ["openid", "profile", "email"]
Air-Gapped Identity¶
Pattern:
# Air-gapped identity
air_gapped_identity:
provider: "local-oidc"
oidc:
issuer: "https://local-idp.airgap.local"
client_id: "local-client"
certificate_authority: "/etc/ssl/ca.pem"
sync:
frequency: "monthly"
method: "secure-media"
OIDC/OAuth2 Patterns¶
Authorization Code Flow¶
Pattern:
# OAuth2 authorization code flow
from authlib.integrations.fastapi_oauth2 import OAuth2
oauth = OAuth2()
@app.get("/login")
async def login():
"""Initiate OAuth2 login"""
redirect_uri = "https://app.example.com/callback"
return await oauth.authorize_redirect(
redirect_uri=redirect_uri,
client_id="client-id",
scope="openid profile email"
)
@app.get("/callback")
async def callback(code: str):
"""OAuth2 callback"""
token = await oauth.authorize_access_token(
code=code,
client_id="client-id",
client_secret="client-secret"
)
return {"access_token": token["access_token"]}
Client Credentials Flow¶
Pattern:
# OAuth2 client credentials flow
async def get_service_token():
"""Get service-to-service token"""
async with httpx.AsyncClient() as client:
response = await client.post(
"https://idp.example.com/token",
data={
"grant_type": "client_credentials",
"client_id": "service-client",
"client_secret": "service-secret",
"scope": "api.read api.write"
}
)
return response.json()["access_token"]
ABAC vs RBAC vs ReBAC¶
RBAC (Role-Based Access Control)¶
Pattern:
# RBAC pattern
rbac:
roles:
- name: "developer"
permissions:
- "read:code"
- "write:code"
- "deploy:staging"
- name: "admin"
permissions:
- "*"
users:
- user: "alice@example.com"
roles: ["developer"]
ABAC (Attribute-Based Access Control)¶
Pattern:
# ABAC pattern
abac:
policies:
- name: "data-access"
conditions:
- attribute: "department"
operator: "equals"
value: "engineering"
- attribute: "clearance"
operator: "gte"
value: "secret"
permissions:
- "read:sensitive-data"
ReBAC (Relationship-Based Access Control)¶
Pattern:
# ReBAC pattern
rebac:
relationships:
- subject: "user:alice"
relation: "owner"
object: "project:alpha"
- subject: "user:bob"
relation: "member"
object: "project:alpha"
policies:
- name: "project-access"
rule: "user can read project if user is owner or member"
Least-Privilege Governance¶
Privilege Minimization¶
Pattern:
# Least-privilege enforcement
class LeastPrivilegeEnforcer:
def enforce(self, user: dict, action: str, resource: str) -> bool:
"""Enforce least-privilege"""
# Get user permissions
permissions = self.get_user_permissions(user)
# Check if action is allowed
required_permission = f"{action}:{resource}"
if required_permission not in permissions:
return False
# Check for excessive permissions
if self.has_excessive_permissions(user):
raise SecurityException("Excessive permissions detected")
return True
Architecture Fitness Functions¶
Identity Consistency Fitness Function¶
Definition:
# Identity consistency fitness function
class IdentityConsistencyFitnessFunction:
def evaluate(self, system: System) -> float:
"""Evaluate identity consistency"""
# Check identity consistency across domains
consistency_score = 0.0
for domain in system.domains:
# Check identity mapping
identity_mapping = self.check_identity_mapping(domain)
# Check token propagation
token_propagation = self.check_token_propagation(domain)
# Calculate domain consistency
domain_consistency = (identity_mapping * 0.5) + \
(token_propagation * 0.5)
consistency_score += domain_consistency
# Average consistency
avg_consistency = consistency_score / len(system.domains)
return avg_consistency
Minimal Privilege Fitness Function¶
Definition:
# Minimal privilege fitness function
class MinimalPrivilegeFitnessFunction:
def evaluate(self, system: System) -> float:
"""Evaluate minimal privilege"""
# Calculate privilege excess
privilege_excess = 0.0
for user in system.users:
# Get user permissions
permissions = self.get_user_permissions(user)
# Get required permissions
required = self.get_required_permissions(user)
# Calculate excess
excess = len(permissions) - len(required)
privilege_excess += excess
# Calculate fitness (lower excess = higher fitness)
if privilege_excess == 0:
fitness = 1.0
else:
fitness = 1.0 / (1.0 + privilege_excess / len(system.users))
return fitness
Secure Delegation Fitness Function¶
Definition:
# Secure delegation fitness function
class SecureDelegationFitnessFunction:
def evaluate(self, system: System) -> float:
"""Evaluate secure delegation"""
# Check delegation patterns
delegation_score = 0.0
for delegation in system.delegations:
# Check token lifetime
token_lifetime = delegation.token_lifetime
if token_lifetime > timedelta(hours=1):
delegation_score -= 0.1
# Check scope limitation
if not delegation.scope_limited:
delegation_score -= 0.1
# Check audit logging
if not delegation.audit_logged:
delegation_score -= 0.1
# Normalize score
fitness = max(0.0, min(1.0, 0.5 + delegation_score))
return fitness
Cross-Document Architecture¶
graph TB
subgraph Identity["Identity Federation<br/>(This Document)"]
Federation["Federation"]
Propagation["Propagation"]
Governance["Governance"]
end
subgraph IAM["IAM & RBAC"]
RBAC["RBAC/ABAC"]
end
subgraph Secure["Secure-by-Design"]
Lifecycle["Security Lifecycle"]
end
subgraph Isolation["Sandboxing"]
MultiTenant["Multi-Tenancy"]
end
Federation --> RBAC
Propagation --> Lifecycle
Governance --> MultiTenant
style Identity fill:#ffebee
style IAM fill:#e1f5ff
style Secure fill:#fff4e1
style Isolation fill:#e8f5e9 Checklists¶
Identity Federation Checklist¶
- Central identity provider configured
- Rancher → RKE2 propagation active
- FastAPI/NiceGUI identity integrated
- Postgres role mapping configured
- FDW identity propagation enabled
- MLflow/MinIO identity configured
- Multi-environment identity strategies defined
- OIDC/OAuth2 patterns implemented
- ABAC/RBAC/ReBAC policies defined
- Least-privilege governance active
- Fitness functions defined
- Regular identity audits scheduled
Anti-Patterns¶
Identity Anti-Patterns¶
Token-Forwarding Leakage:
# Bad: Token forwarding
def forward_token(token: str, service: str):
"""Forward token to service"""
# Token exposed in logs/network
requests.get(service, headers={"Authorization": f"Bearer {token}"})
# Good: Service account
def use_service_account(service: str):
"""Use service account"""
# Service account token (short-lived, scoped)
token = get_service_account_token(service)
requests.get(service, headers={"Authorization": f"Bearer {token}"})
Identity Desync:
# Bad: Identity desync
users:
- name: "alice"
k8s_role: "developer"
postgres_role: "admin" # Mismatch!
# Good: Identity mapping
identity_mapping:
oidc_group: "developers"
k8s_role: "developer"
postgres_role: "app_developer"
# Consistent mapping
See Also¶
- Identity & Access Management, RBAC/ABAC, and Least-Privilege Governance - IAM patterns
- Secure-by-Design Lifecycle Architecture Across Polyglot Systems - Security lifecycle
- Secure Computes, Sandboxing, and Multi-Tenant Isolation for Polyglot Systems - Isolation patterns
- Operational Risk Modeling, Blast Radius Reduction & Failure Domain Architecture - Risk-aware identity
This guide establishes comprehensive identity federation patterns. Start with central identity provider, extend to propagation, and continuously enforce least-privilege governance.