Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 5 additions & 17 deletions charts/controlplane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,25 +343,13 @@ kubectl delete namespace union-cp

## Alternative Deployment Models

### Self-Hosted Intra-Cluster Deployment (AWS)
### Self-Hosted Intra-Cluster Deployment

For deploying Union control plane in the **same Kubernetes cluster** as your Union dataplane, see the dedicated guide:
For deploying Union control plane in the **same Kubernetes cluster** as your Union dataplane, see the [Self-hosted deployment guide](https://docs.union.ai/selfmanaged/deployment/selfhosted-deployment/) on the Union documentation site.

**[Self-Hosted Intra-Cluster Deployment Guide (AWS)](SELFHOSTED_INTRA_CLUSTER_AWS.md)**

This deployment model is ideal for:

- Fully self-hosted Union deployments
- Single-cluster architectures with co-located control plane and dataplane
- Environments requiring simplified networking and reduced costs
- Deployments with strict data sovereignty requirements

The intra-cluster guide covers:

- TLS certificate generation for intra-cluster communication
- Single-tenant mode configuration
- Service discovery between control plane and dataplane
- Complete end-to-end setup for both control plane and dataplane
Reference guides are also available in this repository:
- [AWS](SELFHOSTED_INTRA_CLUSTER_AWS.md)
- [GCP](SELFHOSTED_INTRA_CLUSTER_GCP.md)

---

Expand Down
134 changes: 133 additions & 1 deletion charts/controlplane/SELFHOSTED_INTRA_CLUSTER_AWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
> **Note**: This guide has been migrated to the Union.ai documentation site.
> See: https://docs.union.ai/selfmanaged/deployment/selfhosted-deployment/
> This file is kept for reference but may not be updated.

# Self-Hosted Intra-Cluster Deployment Guide (AWS)

This guide covers deploying Union control plane in the **same Kubernetes cluster** as your Union dataplane (co-located deployment). This is ideal for fully self-hosted Union deployments where both control plane and dataplane run in your infrastructure.
Expand Down Expand Up @@ -211,6 +215,12 @@ global:
ARTIFACT_IAM_ROLE_ARN: "arn:aws:iam::123456789012:role/union-artifacts"
FLYTEADMIN_IAM_ROLE_ARN: "arn:aws:iam::123456789012:role/union-flyteadmin"
UNION_ORG: "my-company"
# Authentication (see Authentication section below)
OIDC_BASE_URL: "https://your-idp.example.com/oauth2/default"
OIDC_CLIENT_ID: "<browser-login-client-id>"
CLI_CLIENT_ID: "<cli-client-id>"
INTERNAL_CLIENT_ID: "<service-to-service-client-id>"
AUTH_TOKEN_URL: "https://your-idp.example.com/oauth2/default/v1/token"
```

**Important notes:**
Expand Down Expand Up @@ -284,6 +294,128 @@ Control plane services discover each other via Kubernetes DNS:
- **NGINX Ingress**: `controlplane-nginx-controller.union-cp.svc.cluster.local`
- **Dataplane** (for dataproxy): `dataplane-nginx-controller.union.svc.cluster.local`

## Authentication (OIDC/OAuth2)

Union supports OIDC-based authentication for self-hosted deployments. When enabled, all API calls (browser, CLI, and service-to-service) are authenticated via an external OAuth2/OIDC provider.

### Overview

Authentication uses an external OAuth2/OIDC-compliant identity provider. You will need to create **three OAuth2 client applications** in your identity provider:

| Client | Flow | Type | Purpose |
|--------|------|------|---------|
| Browser login | Authorization Code | Confidential | Console/web UI authentication |
| CLI | Authorization Code + PKCE | Public | `flytectl` / `uctl` CLI authentication |
| Service-to-service | Client Credentials | Confidential | Internal service authentication |

### OIDC Provider Requirements

Your OIDC provider must support:

1. **OpenID Connect Discovery** — `/.well-known/openid-configuration` endpoint
2. **Authorization Code flow** — for browser and CLI login
3. **Client Credentials flow** — for service-to-service tokens
4. **PKCE** (Proof Key for Code Exchange) — for the CLI public client
5. **Custom scopes** — ability to create an `all` scope (or equivalent)

### Step-by-Step Configuration

#### 1. Create OAuth2 Applications

Create three applications in your identity provider:

**Browser Login App (Confidential):**
- Grant type: Authorization Code
- Redirect URI: `https://<your-domain>/callback` (or the control plane ingress host)
- Scopes: `openid`, `profile`, `offline_access`
- Note the **Client ID** → used as `OIDC_CLIENT_ID`

**CLI App (Public):**
- Grant type: Authorization Code + PKCE
- Redirect URI: `http://localhost:53593/callback`
- Scopes: `all`
- Note the **Client ID** → used as `CLI_CLIENT_ID`

**Service-to-Service App (Confidential):**
- Grant type: Client Credentials
- Scopes: `all`
- Note the **Client ID** → used as `INTERNAL_CLIENT_ID`
- Note the **Client Secret** → stored in Kubernetes secrets

#### 2. Set Authentication Globals

Add the following to your customer overrides file:

```yaml
global:
# ... existing globals ...
OIDC_BASE_URL: "https://your-idp.example.com/oauth2/default"
OIDC_CLIENT_ID: "<browser-login-client-id>"
CLI_CLIENT_ID: "<cli-client-id>"
INTERNAL_CLIENT_ID: "<service-to-service-client-id>"
AUTH_TOKEN_URL: "https://your-idp.example.com/oauth2/default/v1/token"
```

#### 3. Create Kubernetes Secrets

The control plane needs the service-to-service client secret in two Kubernetes secrets:

```bash
# Secret for flyteadmin (mounted at /etc/secrets/)
kubectl create secret generic flyte-admin-secrets \
--from-literal=client_secret='<SERVICE_CLIENT_SECRET>' \
-n union-cp

# Secret for flyte-scheduler (mounted at /etc/secrets/)
kubectl create secret generic flyte-secret-auth \
--from-literal=client_secret='<SERVICE_CLIENT_SECRET>' \
-n union-cp
```

Union control plane services (executions, cluster, usage, etc.) mount secrets at `/etc/secrets/union/`. Create or update the main service secret:

```bash
# If using the union-controlplane-secrets secret, add client_secret key:
kubectl create secret generic union-controlplane-secrets \
--from-literal=pass.txt='<DB_PASSWORD>' \
--from-literal=client_secret='<SERVICE_CLIENT_SECRET>' \
-n union-cp --dry-run=client -o yaml | kubectl apply -f -
```

**Tip:** For production, use External Secrets Operator or a similar tool to sync secrets from your cloud provider's secret manager (AWS Secrets Manager, GCP Secret Manager, Azure Key Vault).

#### 4. Enable Authentication in FlyteAdmin

To activate the OIDC login endpoints (`/login`, `/callback`, `/me`), add the following to your customer overrides:

```yaml
flyte:
configmap:
adminServer:
server:
security:
useAuth: true
```

This enables nginx auth-subrequest validation on protected ingress routes.

### Verifying Authentication

After deploying with auth enabled:

```bash
# Check flyteadmin logs for auth initialization
kubectl logs -n union-cp deploy/flyteadmin | grep -i auth

# Test the /me endpoint (should return 401 without a token)
kubectl exec -n union-cp deploy/flyteadmin -- \
curl -s -o /dev/null -w "%{http_code}" https://controlplane-nginx-controller.union-cp.svc.cluster.local/me -k

# Test CLI login
uctl config init --host https://<your-domain>
uctl get project
```

## Architecture Diagram

```mermaid
Expand Down Expand Up @@ -418,7 +550,7 @@ kubectl logs -n union-cp deploy/controlplane-nginx-controller
## Next Steps

1. **Deploy Dataplane**: Follow the [Dataplane Intra-Cluster Guide](../dataplane/SELFHOST_INTRA_CLUSTER_AWS.md)
2. **Configure Users**: Set up user authentication and RBAC
2. **Enable Authentication**: Follow the [Authentication (OIDC/OAuth2)](#authentication-oidcoauth2) section above
3. **Test Workflows**: Run a test workflow to verify the complete stack
4. **Set Up Monitoring**: Configure Prometheus and Grafana for observability

Expand Down
134 changes: 133 additions & 1 deletion charts/controlplane/SELFHOSTED_INTRA_CLUSTER_GCP.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
> **Note**: This guide has been migrated to the Union.ai documentation site.
> See: https://docs.union.ai/selfmanaged/deployment/selfhosted-deployment/
> This file is kept for reference but may not be updated.

# Self-Hosted Intra-Cluster Deployment Guide (GCP)

This guide covers deploying Union control plane in the **same Kubernetes cluster** as your Union dataplane (co-located deployment). This is ideal for fully self-hosted Union deployments where both control plane and dataplane run in your infrastructure.
Expand Down Expand Up @@ -223,6 +227,12 @@ global:
FLYTEADMIN_IAM_ROLE_ARN: "[email protected]"
UNION_ORG: "my-company"
GOOGLE_PROJECT_ID: "my-gcp-project"
# Authentication (see Authentication section below)
OIDC_BASE_URL: "https://your-idp.example.com/oauth2/default"
OIDC_CLIENT_ID: "<browser-login-client-id>"
CLI_CLIENT_ID: "<cli-client-id>"
INTERNAL_CLIENT_ID: "<service-to-service-client-id>"
AUTH_TOKEN_URL: "https://your-idp.example.com/oauth2/default/v1/token"
```

**Important notes:**
Expand Down Expand Up @@ -296,6 +306,128 @@ Control plane services discover each other via Kubernetes DNS:
- **NGINX Ingress**: `controlplane-nginx-controller.union-cp.svc.cluster.local`
- **Dataplane** (for dataproxy): `dataplane-nginx-controller.union.svc.cluster.local`

## Authentication (OIDC/OAuth2)

Union supports OIDC-based authentication for self-hosted deployments. When enabled, all API calls (browser, CLI, and service-to-service) are authenticated via an external OAuth2/OIDC provider.

### Overview

Authentication uses an external OAuth2/OIDC-compliant identity provider. You will need to create **three OAuth2 client applications** in your identity provider:

| Client | Flow | Type | Purpose |
|--------|------|------|---------|
| Browser login | Authorization Code | Confidential | Console/web UI authentication |
| CLI | Authorization Code + PKCE | Public | `flytectl` / `uctl` CLI authentication |
| Service-to-service | Client Credentials | Confidential | Internal service authentication |

### OIDC Provider Requirements

Your OIDC provider must support:

1. **OpenID Connect Discovery** — `/.well-known/openid-configuration` endpoint
2. **Authorization Code flow** — for browser and CLI login
3. **Client Credentials flow** — for service-to-service tokens
4. **PKCE** (Proof Key for Code Exchange) — for the CLI public client
5. **Custom scopes** — ability to create an `all` scope (or equivalent)

### Step-by-Step Configuration

#### 1. Create OAuth2 Applications

Create three applications in your identity provider:

**Browser Login App (Confidential):**
- Grant type: Authorization Code
- Redirect URI: `https://<your-domain>/callback` (or the control plane ingress host)
- Scopes: `openid`, `profile`, `offline_access`
- Note the **Client ID** → used as `OIDC_CLIENT_ID`

**CLI App (Public):**
- Grant type: Authorization Code + PKCE
- Redirect URI: `http://localhost:53593/callback`
- Scopes: `all`
- Note the **Client ID** → used as `CLI_CLIENT_ID`

**Service-to-Service App (Confidential):**
- Grant type: Client Credentials
- Scopes: `all`
- Note the **Client ID** → used as `INTERNAL_CLIENT_ID`
- Note the **Client Secret** → stored in Kubernetes secrets

#### 2. Set Authentication Globals

Add the following to your customer overrides file:

```yaml
global:
# ... existing globals ...
OIDC_BASE_URL: "https://your-idp.example.com/oauth2/default"
OIDC_CLIENT_ID: "<browser-login-client-id>"
CLI_CLIENT_ID: "<cli-client-id>"
INTERNAL_CLIENT_ID: "<service-to-service-client-id>"
AUTH_TOKEN_URL: "https://your-idp.example.com/oauth2/default/v1/token"
```

#### 3. Create Kubernetes Secrets

The control plane needs the service-to-service client secret in two Kubernetes secrets:

```bash
# Secret for flyteadmin (mounted at /etc/secrets/)
kubectl create secret generic flyte-admin-secrets \
--from-literal=client_secret='<SERVICE_CLIENT_SECRET>' \
-n union-cp

# Secret for flyte-scheduler (mounted at /etc/secrets/)
kubectl create secret generic flyte-secret-auth \
--from-literal=client_secret='<SERVICE_CLIENT_SECRET>' \
-n union-cp
```

Union control plane services (executions, cluster, usage, etc.) mount secrets at `/etc/secrets/union/`. Create or update the main service secret:

```bash
# If using the union-controlplane-secrets secret, add client_secret key:
kubectl create secret generic union-controlplane-secrets \
--from-literal=pass.txt='<DB_PASSWORD>' \
--from-literal=client_secret='<SERVICE_CLIENT_SECRET>' \
-n union-cp --dry-run=client -o yaml | kubectl apply -f -
```

**Tip:** For production, use External Secrets Operator or a similar tool to sync secrets from your cloud provider's secret manager (AWS Secrets Manager, GCP Secret Manager, Azure Key Vault).

#### 4. Enable Authentication in FlyteAdmin

To activate the OIDC login endpoints (`/login`, `/callback`, `/me`), add the following to your customer overrides:

```yaml
flyte:
configmap:
adminServer:
server:
security:
useAuth: true
```

This enables nginx auth-subrequest validation on protected ingress routes.

### Verifying Authentication

After deploying with auth enabled:

```bash
# Check flyteadmin logs for auth initialization
kubectl logs -n union-cp deploy/flyteadmin | grep -i auth

# Test the /me endpoint (should return 401 without a token)
kubectl exec -n union-cp deploy/flyteadmin -- \
curl -s -o /dev/null -w "%{http_code}" https://controlplane-nginx-controller.union-cp.svc.cluster.local/me -k

# Test CLI login
uctl config init --host https://<your-domain>
uctl get project
```

## Architecture Diagram

```mermaid
Expand Down Expand Up @@ -452,7 +584,7 @@ kubectl logs -n union-cp deploy/controlplane-nginx-controller
## Next Steps

1. **Deploy Dataplane**: Follow the [Dataplane Intra-Cluster Guide](../dataplane/SELFHOST_INTRA_CLUSTER_GCP.md)
2. **Configure Users**: Set up user authentication and RBAC
2. **Enable Authentication**: Follow the [Authentication (OIDC/OAuth2)](#authentication-oidcoauth2) section above
3. **Test Workflows**: Run a test workflow to verify the complete stack
4. **Set Up Monitoring**: Configure Prometheus and Grafana for observability

Expand Down
4 changes: 2 additions & 2 deletions charts/controlplane/templates/common/_ingress-protected.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ metadata:
{{- end }}
{{- end }}
{{- with .Values.ingress.protectedIngressAnnotationsGrpc }}
{{- toYaml . | nindent 4 }}
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end}}
spec:
{{- with .Values.ingress.className }}
Expand Down Expand Up @@ -1550,7 +1550,7 @@ metadata:
{{- end }}
{{- end }}
{{- with .Values.ingress.protectedIngressAnnotationsGrpc }}
{{- toYaml . | nindent 4 }}
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end}}
spec:
{{- with .Values.ingress.className }}
Expand Down
2 changes: 1 addition & 1 deletion charts/controlplane/templates/common/_usage-ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ metadata:
{{- end }}
{{- end }}
{{- with .Values.ingress.protectedIngressAnnotationsGrpc }}
{{- toYaml . | nindent 4 }}
{{- tpl (toYaml .) $ | nindent 4 }}
{{- end}}
{{- if not .Values.services.usage.configMap.billing.enable }}
nginx.ingress.kubernetes.io/use-regex: "true"
Expand Down
Loading