Aletyx Decision Control Tower Setup Guide¶
This guide covers deploying Aletyx Decision Control Tower in your Kubernetes cluster with production-ready configurations.
Prerequisites
Before deploying Aletyx Decision Control Tower, ensure you have:
- Kubernetes cluster v1.24+
- Decision Control environments deployed (dev, test, prod)
- Keycloak configured with the
aletyxrealm - Ingress controller with TLS support
- DNS entries for Aletyx Decision Control Tower hostname
Architecture Overview¶
Aletyx Decision Control Tower consists of three main components that work together to provide unified governance across your Decision Control environments.
Step 1: Create Namespace and Service Account¶
Create a dedicated namespace for Aletyx Decision Control Tower:
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: decision-control
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: control-tower-sa
namespace: decision-control
Apply:
Step 2: Configure Container Registry Access¶
Create an image pull secret for accessing container images:
kubectl create secret docker-registry aletyx-registry \
--docker-server=registry-{{ edition }}.aletyx.services \
--docker-username=YOUR_EMAIL \
--docker-password=YOUR_TOKEN \
--namespace=decision-control
Registry Credentials
Obtain your registry credentials from my.aletyx.ai. Navigate to Container Images to find your username (email) and authentication token for your subscription edition.
Step 3: Deploy Governance Database¶
Deploy PostgreSQL for governance data:
# governance-database.yaml
apiVersion: v1
kind: Secret
metadata:
name: postgres-governance-secret
namespace: decision-control
type: Opaque
stringData:
POSTGRES_USER: governance_user
POSTGRES_PASSWORD: "CHANGE_ME_SECURE_PASSWORD"
POSTGRES_DB: governance_db
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-governance-pvc
namespace: decision-control
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-governance
namespace: decision-control
spec:
replicas: 1
selector:
matchLabels:
app: postgres-governance
template:
metadata:
labels:
app: postgres-governance
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-governance-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-governance-secret
key: POSTGRES_PASSWORD
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgres-governance-secret
key: POSTGRES_DB
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
exec:
command: ["pg_isready", "-U", "governance_user"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["pg_isready", "-U", "governance_user"]
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-governance-pvc
---
apiVersion: v1
kind: Service
metadata:
name: postgres-governance
namespace: decision-control
spec:
selector:
app: postgres-governance
ports:
- port: 5432
targetPort: 5432
Apply:
Production Considerations
For production deployments, consider using managed PostgreSQL services (AWS RDS, Google Cloud SQL, Azure Database) with automated backups and high availability.
Step 4: Deploy Governance API¶
The Governance API provides the backend services for workflow management:
# governance-api.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: governance-api-config
namespace: decision-control
data:
DB_HOST: "postgres-governance"
DB_PORT: "5432"
DB_NAME: "governance_db"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: governance-api
namespace: decision-control
labels:
app: governance-api
spec:
replicas: 1
selector:
matchLabels:
app: governance-api
template:
metadata:
labels:
app: governance-api
spec:
serviceAccountName: control-tower-sa
imagePullSecrets:
- name: aletyx-registry
containers:
- name: governance-api
image: registry-{{ edition }}.aletyx.services/governance-api:1.2.1
imagePullPolicy: Always
ports:
- containerPort: 3000
name: http
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "3000"
- name: AUTH_PROVIDER
value: "keycloak"
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: governance-api-config
key: DB_HOST
- name: DB_PORT
valueFrom:
configMapKeyRef:
name: governance-api-config
key: DB_PORT
- name: DB_NAME
valueFrom:
configMapKeyRef:
name: governance-api-config
key: DB_NAME
- name: DB_USER
valueFrom:
secretKeyRef:
name: postgres-governance-secret
key: POSTGRES_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-governance-secret
key: POSTGRES_PASSWORD
- name: KEYCLOAK_URL
value: "https://keycloak.your-domain.com"
- name: KEYCLOAK_REALM
value: "aletyx"
- name: KEYCLOAK_CLIENT_ID
value: "decision-control"
- name: APP_BASE_URL
value: "https://control-tower.your-domain.com"
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: governance-api
namespace: decision-control
spec:
selector:
app: governance-api
ports:
- port: 3000
targetPort: 3000
Apply:
Step 5: Deploy Control Tower¶
Deploy the Aletyx Decision Control Tower frontend and API gateway:
# control-tower.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: control-tower-config
namespace: decision-control
data:
env.js: |
window.__ENV__ = {
KEYCLOAK_URL: 'https://keycloak.your-domain.com',
KEYCLOAK_REALM: 'aletyx',
KEYCLOAK_CLIENT_ID: 'decision-control'
};
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: control-tower
namespace: decision-control
labels:
app: control-tower
spec:
replicas: 1
selector:
matchLabels:
app: control-tower
template:
metadata:
labels:
app: control-tower
spec:
serviceAccountName: control-tower-sa
imagePullSecrets:
- name: aletyx-registry
containers:
- name: control-tower
image: registry-{{ edition }}.aletyx.services/control-tower:1.2.1
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "8080"
- name: GOVERNANCE_API_URL
value: "http://governance-api:3000"
- name: AUTH_PROVIDER
value: "keycloak"
- name: KEYCLOAK_URL
value: "https://keycloak.your-domain.com"
- name: KEYCLOAK_REALM
value: "aletyx"
volumeMounts:
- name: config
mountPath: /app/public/config/env.js
subPath: env.js
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
volumes:
- name: config
configMap:
name: control-tower-config
---
apiVersion: v1
kind: Service
metadata:
name: control-tower
namespace: decision-control
spec:
selector:
app: control-tower
ports:
- port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: control-tower
namespace: decision-control
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
ingressClassName: nginx
tls:
- hosts:
- control-tower.your-domain.com
secretName: control-tower-tls
rules:
- host: control-tower.your-domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: control-tower
port:
number: 80
Apply:
Step 6: Configure Keycloak¶
Create Client¶
In Keycloak admin console (https://keycloak.your-domain.com/admin):
-
Select Realm:
aletyx -
Create Client:
- Client ID:
decision-control - Client type:
OpenID Connect - Client authentication:
Off(public client)
- Client ID:
-
Configure Settings:
- Standard flow:
Enabled - Valid redirect URIs:
https://control-tower.your-domain.com/* - Valid post logout redirect URIs:
https://control-tower.your-domain.com/* - Web origins:
https://control-tower.your-domain.com
- Standard flow:
Create Realm Roles¶
Create these roles in the aletyx realm:
| Role | Description | Typical Users |
|---|---|---|
decision-control-dev-users |
Access to DEV environment | Business Analysts |
decision-control-risk-manager |
Risk approval authority | Risk Managers |
decision-control-compliance |
Compliance approval authority | Compliance Officers |
decision-control-prod-users |
Access to PROD environment | Operations Managers |
decision-control-admin |
Full administrative access | Administrators |
Create Test Users¶
Step 7: Verify Deployment¶
Check all pods are running:
kubectl get pods -n decision-control
# Expected output:
# NAME READY STATUS RESTARTS AGE
# control-tower-xxx 1/1 Running 0 2m
# governance-api-xxx 1/1 Running 0 3m
# postgres-governance-xxx 1/1 Running 0 5m
Test endpoints:
# Control Tower health
curl -s https://control-tower.your-domain.com/health
# Governance API health
kubectl exec -n decision-control deploy/control-tower -- \
wget -qO- http://governance-api:3000/health
Step 8: First Login¶
- Navigate to
https://control-tower.your-domain.com - Click "Sign In" - you'll be redirected to Keycloak
- Authenticate with a user that has Decision Control roles
- After authentication, the dashboard displays your accessible environments
Verification Checklist
- Login redirects to Keycloak
- Dashboard loads after authentication
- Environments display based on user roles
- Navigation between environments works
Configuration Reference¶
Environment Variables¶
Control Tower¶
| Variable | Description | Example |
|---|---|---|
GOVERNANCE_API_URL |
Internal URL to Governance API | http://governance-api:3000 |
AUTH_PROVIDER |
Authentication provider | keycloak |
KEYCLOAK_URL |
Public Keycloak URL | https://keycloak.example.com |
KEYCLOAK_REALM |
Keycloak realm name | aletyx |
Governance API¶
| Variable | Description | Example |
|---|---|---|
DB_HOST |
PostgreSQL host | postgres-governance |
DB_PORT |
PostgreSQL port | 5432 |
DB_NAME |
Database name | governance_db |
DB_USER |
Database username | governance_user |
DB_PASSWORD |
Database password | (from secret) |
APP_BASE_URL |
Public Aletyx Decision Control Tower URL | https://control-tower.example.com |
Updating Configuration¶
To update Aletyx Decision Control Tower configuration:
# Update ConfigMap
kubectl delete configmap control-tower-config -n decision-control
kubectl create configmap control-tower-config \
--from-file=env.js=./env.js \
--namespace=decision-control
# Restart deployment
kubectl rollout restart deployment/control-tower -n decision-control
Troubleshooting¶
Cannot Log In¶
- Verify Keycloak client redirect URIs include
https://control-tower.your-domain.com/* - Check Governance API logs:
- Verify Keycloak is accessible from the cluster
Environments Not Loading¶
- Verify Governance API is running
- Check database connectivity:
- Review environment configuration in database
Tasks Not Appearing¶
- Ensure user has correct role assignment in Keycloak
- Verify governance workflow is configured
- Check Governance API logs for errors
Next Steps¶
- Dashboard Overview: Navigate the interface
- Environment Management: Configure Decision Control environments
- Task Management: Work with governance tasks
- Governance Workflow: Configure approval workflows