AuthGateway¶
API Version: e6data.io/v1alpha1 Kind: AuthGateway Short Names: ag
1. Purpose¶
AuthGateway manages a Pomerium-based authentication gateway for protecting E6Data services. It provides:
- Identity-aware access control via multiple identity providers (Google, Okta, Azure AD, GitHub, OIDC)
- Passthrough mode for development/testing (routing without authentication)
- Modular service routing with subdomain or path-based access
- Per-service policy overrides for fine-grained access control
AuthGateway is separate from TrafficInfra: - TrafficInfra = xDS + Envoy (QueryService gRPC traffic routing) - AuthGateway = Pomerium (authentication gateway for any service)
This separation allows independent scaling, flexible deployment order, and protecting multiple services through a single gateway.
Note: Infrastructure settings (tolerations, nodeSelector, affinity, imagePullSecrets) are inherited from NamespaceConfig in the same namespace.
2. High-level Behavior¶
When you create an AuthGateway CR, the operator:
- Inherits infrastructure settings from NamespaceConfig
- Deploys Pomerium proxy for identity-aware routing
- Configures service routes based on spec.services
- Creates TLS certificates if cert-manager is enabled
- Exposes LoadBalancer service for external access
Architecture¶
┌─────────────────────────────────────────┐
│ AuthGateway (Pomerium) │
│ │
Internet ──────────▶│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ query.* │ │ api.* │ │ /* │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
└───────┼───────────┼───────────┼───────┘
│ │ │
▼ ▼ ▼
┌───────────┐ ┌─────────┐ ┌─────────┐
│TrafficInfra│ │API Server│ │ UI │
│ (Envoy) │ │ │ │ │
└─────┬─────┘ └─────────┘ └─────────┘
│
▼
┌───────────┐
│QueryService│
│ (Planners) │
└───────────┘
Prerequisites¶
- NamespaceConfig must exist in the same namespace
- IDP credentials secret must exist (if authentication enabled)
- Backend services should exist (can be deployed after AuthGateway)
Child Resources Created¶
| Resource Type | Name Pattern | Purpose |
|---|---|---|
| ConfigMap | {name}-pomerium-config | Pomerium configuration |
| Deployment | {name}-pomerium | Pomerium proxy pods |
| Service | {name}-pomerium | External HTTPS endpoint |
| Certificate | {name}-pomerium-cert | TLS certificate (if cert-manager enabled) |
3. Spec Reference¶
3.1 Top-level Fields¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
domain | string | Yes | - | Base domain for all services |
replicas | int32 | No | 2 | Number of Pomerium replicas |
image | ImageSpec | No | pomerium:v0.27.0 | Pomerium image configuration |
resources | ResourceSpec | No | 500m/256Mi | Resource requirements |
authentication | AuthenticationSpec | No | disabled | Authentication configuration |
tls | TLSSpec | No | - | TLS configuration |
service | ServiceSpec | No | LoadBalancer | Service exposure |
services | []ServiceRouteSpec | No | [] | Service routes to protect |
3.2 Image¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
repository | string | No | pomerium | Image registry |
name | string | No | pomerium | Image name |
tag | string | No | v0.27.0 | Image tag |
pullPolicy | string | No | IfNotPresent | Pull policy |
3.3 Resources¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
cpu | string | No | 500m | CPU request/limit |
memory | string | No | 256Mi | Memory request/limit |
3.4 Authentication¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
enabled | bool | No | false | Enable authentication (false = passthrough mode) |
idp | IDPSpec | No | - | Identity provider configuration |
policy | PolicySpec | No | - | Global access policy |
3.4.1 IDP¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
provider | string | No | - | Provider type: google, okta, azure, github, oidc |
credentialsSecretRef.name | string | No | - | Secret with IDP_CLIENT_ID and IDP_CLIENT_SECRET |
issuerURL | string | No | - | OIDC issuer URL (required for okta, oidc) |
3.4.2 Policy¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
allowedDomains | []string | No | [] | Allowed email domains |
allowedEmails | []string | No | [] | Allowed email addresses |
allowedGroups | []string | No | [] | Allowed groups (requires IDP group sync) |
3.5 TLS¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
certManager.enabled | bool | No | false | Use cert-manager |
certManager.issuerRef.name | string | No | - | Issuer name |
certManager.issuerRef.kind | string | No | ClusterIssuer | Issuer or ClusterIssuer |
secretName | string | No | - | Pre-existing TLS secret |
3.6 Service¶
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | No | LoadBalancer | Service type |
annotations | map | No | {} | Service annotations |
3.7 Services¶
Each service route defines a backend to protect:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Unique route identifier |
enabled | bool | No | true | Enable this route |
subdomain | string | No | - | Subdomain routing (e.g., query → query.domain.com) |
pathPrefix | string | No | - | Path routing (e.g., /api → domain.com/api/*) |
backend.serviceName | string | Yes | - | Backend Kubernetes service |
backend.servicePort | int32 | Yes | - | Backend service port |
backend.namespace | string | No | same | Backend namespace |
timeout | string | No | 30s | Request timeout |
allowWebsockets | bool | No | false | Enable WebSocket/gRPC-web |
preserveHostHeader | bool | No | false | Preserve original Host header |
policy | PolicySpec | No | - | Override global policy for this route |
4. Status Reference¶
| Field | Type | Description |
|---|---|---|
phase | string | Current phase (Pending, Deploying, Ready, Degraded, Failed) |
message | string | Human-readable status message |
endpoint | string | External gateway URL |
authenticationEnabled | bool | Whether authentication is active |
pomeriumReady | bool | Pomerium deployment is ready |
certificateReady | bool | TLS certificate is ready |
services | []ServiceRouteStatus | Per-service status |
conditions | []Condition | Detailed conditions |
observedGeneration | int64 | Generation observed by controller |
lastTransitionTime | Time | Last status transition |
5. Example CRs¶
Minimal (Passthrough Mode)¶
For testing without authentication:
apiVersion: e6data.io/v1alpha1
kind: AuthGateway
metadata:
name: auth
namespace: workspace-dev
spec:
domain: dev.internal.example.com
authentication:
enabled: false # Passthrough mode
service:
type: ClusterIP
services:
- name: query
subdomain: query
backend:
serviceName: envoy
servicePort: 8080
Production (with Authentication)¶
apiVersion: e6data.io/v1alpha1
kind: AuthGateway
metadata:
name: auth
namespace: workspace-prod
spec:
domain: e6data.example.com
replicas: 2
authentication:
enabled: true
idp:
provider: google
credentialsSecretRef:
name: pomerium-idp-credentials
policy:
allowedDomains:
- "yourcompany.com"
tls:
certManager:
enabled: true
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
service:
type: LoadBalancer
services:
# Query Engine (via TrafficInfra Envoy)
- name: query
enabled: true
subdomain: query
backend:
serviceName: envoy
servicePort: 8080
timeout: "300s"
allowWebsockets: true
# API Server
- name: api
enabled: true
subdomain: api
backend:
serviceName: e6-apiserver
servicePort: 8080
# UI Dashboard
- name: ui
enabled: true
pathPrefix: /
backend:
serviceName: e6-ui
servicePort: 3000
Multi-IDP (Okta)¶
apiVersion: e6data.io/v1alpha1
kind: AuthGateway
metadata:
name: auth
namespace: workspace-prod
spec:
domain: query.mycompany.com
authentication:
enabled: true
idp:
provider: okta
credentialsSecretRef:
name: okta-credentials
issuerURL: "https://mycompany.okta.com"
policy:
allowedGroups:
- "engineering"
- "data-team"
services:
- name: query
backend:
serviceName: envoy
servicePort: 8080
6. Identity Provider Configuration¶
Google Workspace¶
- Create OAuth 2.0 credentials in Google Cloud Console
- Set authorized redirect URI:
https://authenticate.<domain>/oauth2/callback - Create secret:
kubectl create secret generic pomerium-idp-credentials \
--namespace=workspace-prod \
--from-literal=IDP_CLIENT_ID="<client-id>.apps.googleusercontent.com" \
--from-literal=IDP_CLIENT_SECRET="<client-secret>"
Okta¶
- Create OIDC application in Okta Admin Console
- Set redirect URI:
https://authenticate.<domain>/oauth2/callback - Create secret with credentials and set
issuerURL
Azure AD¶
- Register application in Azure Portal
- Add redirect URI:
https://authenticate.<domain>/oauth2/callback - Create secret with Application (client) ID and client secret
7. Relationship with TrafficInfra¶
AuthGateway can route traffic to TrafficInfra's Envoy for authenticated query access:
services:
- name: query
subdomain: query
backend:
serviceName: envoy # TrafficInfra's Envoy service
servicePort: 8080
timeout: "300s"
allowWebsockets: true # For gRPC-web
preserveHostHeader: true
Deployment Order: AuthGateway does NOT require TrafficInfra to exist first. If the backend service isn't available, the route shows as "pending" until TrafficInfra is deployed.
8. Troubleshooting¶
Common Issues¶
| Symptom | Possible Cause | Solution |
|---|---|---|
| 401 Unauthorized | IDP misconfigured | Check credentials secret and redirect URI |
| 403 Forbidden | Policy mismatch | Verify allowedDomains/allowedGroups |
| Certificate error | TLS not ready | Check cert-manager logs and Certificate CR |
| Backend unreachable | Service not found | Verify backend service exists |
Debugging Commands¶
# Check AuthGateway status
kubectl get authgateways -n workspace-prod
kubectl describe authgateway auth -n workspace-prod
# Check Pomerium pods
kubectl get pods -n workspace-prod -l app=pomerium
kubectl logs -n workspace-prod -l app=pomerium
# Check TLS certificate (if using cert-manager)
kubectl get certificates -n workspace-prod
# Check IDP credentials secret
kubectl get secret pomerium-idp-credentials -n workspace-prod -o yaml
9. Cloud-Specific LoadBalancer Configuration¶
AWS Network Load Balancer (NLB)¶
For AWS with SSL termination at the NLB:
apiVersion: e6data.io/v1alpha1
kind: AuthGateway
metadata:
name: auth
namespace: workspace-prod
spec:
domain: query.example.com
replicas: 2
service:
type: LoadBalancer
loadBalancerClass: service.k8s.aws/nlb
annotations:
# NLB configuration
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
# SSL/TLS termination at NLB
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:<REGION>:<ACCOUNT_ID>:certificate/<CERTIFICATE_ID>"
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
# HTTP/2 support for gRPC
service.beta.kubernetes.io/aws-load-balancer-alpn-policy: HTTP2Only
services:
- name: query
enabled: true
isGRPC: true
subdomain: query
timeout: "30s"
backend:
serviceName: workspace-prod-traffic-envoy
servicePort: 8080
AWS NLB Annotations Reference¶
| Annotation | Description | Values |
|---|---|---|
aws-load-balancer-scheme | Internet or internal facing | internet-facing, internal |
aws-load-balancer-nlb-target-type | Target type for NLB | ip, instance |
aws-load-balancer-ssl-cert | ACM certificate ARN | arn:aws:acm:... |
aws-load-balancer-ssl-ports | Ports for SSL termination | 443 |
aws-load-balancer-alpn-policy | ALPN policy for HTTP/2 | HTTP2Only, HTTP2Optional, HTTP1Only, None |
Internal NLB (Private Access)¶
For private/internal access only:
service:
type: LoadBalancer
loadBalancerClass: service.k8s.aws/nlb
annotations:
service.beta.kubernetes.io/aws-load-balancer-scheme: internal
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:..."
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
GCP Load Balancer¶
For GCP with managed SSL certificate:
service:
type: LoadBalancer
annotations:
networking.gke.io/load-balancer-type: External
cloud.google.com/neg: '{"ingress": true}'
Azure Load Balancer¶
For Azure with internal load balancer:
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
10. Singleton Constraint¶
Only one AuthGateway is allowed per namespace. The webhook validates this constraint on create.
If you need multiple authentication configurations, use separate namespaces.