Skip to content
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ We try to BEST-EFFORT support each release for 6 months as community. There is [
- [Overview of the Kubeflow Platform](#overview-of-the-kubeflow-platform)
- [Kubeflow Components Versions](#kubeflow-components-versions)
- [Installation](#installation)
- [Security Considerations](#security-considerations)
- [Prerequisites](#prerequisites)
- [Install with a Single Command](#install-with-a-single-command)
- [Install Individual Components](#install-individual-components)
Expand All @@ -27,7 +28,7 @@ We try to BEST-EFFORT support each release for 6 months as community. There is [
- [Change Default User Password](#change-default-user-password)
- [Upgrading and Extending](#upgrading-and-extending)
- [Release Process](#release-process)
- [Security](#security)
- [Security](#security)
- [Pre-commit Hooks](#pre-commit-hooks)
- [Architecture](#architecture)
- [Frequently Asked Questions](#frequently-asked-questions)
Expand Down Expand Up @@ -90,9 +91,25 @@ We provide two options for installing the official Kubeflow components and commo

The `example` directory contains an example kustomization for the single command to be able to run.

:warning: In both options, we use a default email (`user@example.com`) and password (`12341234`). For any production Kubeflow deployment, you should change the default password by following [the relevant section](#change-default-user-password).
### Security Considerations

:warning: For any production Kubeflow deployment, you must take additional steps to ensure a secure setup of your Kubeflow environment. The following list highlights important security measures, but it may not be exhaustive:

- The setup comes with a default email (`user@example.com`) and password (`12341234`). You should change the default password by following [the relevant section](#change-default-user-password).
- Change `OIDC_CLIENT_SECRET` in [Dex](common/dex/base/secret_params.env), set the matching `client-secret` in [OAuth2 Proxy](common/oauth2-proxy/base/kustomization.yaml), and replace the OAuth2 Proxy [`cookie-secret`](common/oauth2-proxy/base/kustomization.yaml).
- Support for [Pod Security Admission is enabled](https://kubernetes.io/docs/concepts/security/pod-security-admission/), so that the Pod Security Standards
will be enforced [in the user's profile and workloads](applications/dashboard/upstream/profile-controller/overlays/kubeflow-pss/namespace-labels-kubeflow-pss.yaml). This helps prevent container breakouts and cluster privilege escalation.
- Network Policies are included. Ensure that the cluster uses a [network plugin that enforces them](https://kubernetes.io/docs/concepts/services-networking/network-policies/#prerequisites), and verify their enforcement. Without enforcement, users may bypass security controls by communicating with central services.
- Secure the Kubeflow Gateway: Enable HTTPS, make port 80 redirect to HTTPS, and enable `FORCE_HTTPS` in the file [`common/oauth2-proxy/base/kustomization.yaml`](common/oauth2-proxy/base/kustomization.yaml) as described in [`common/oauth2-proxy/components/README.md`](common/oauth2-proxy/components/README.md#using-https).
- Configure [the secure Notebook setup](proposals/20260705-secure-notebook-setup.md). This hosts notebooks on a different subdomain, which helps prevent session hijacking through a malicious notebook.
- If you do not use ``oauth2-proxy`` for authentication or Istio in ambient mode (since the ``EnvoyFilter`` is not supported there), ensure that you filter all authentication cookies from requests sent to Notebooks (take a look at [``envoy-filter-gateway.yaml``](common/istio/istio-install/overlays/oauth2-proxy/envoy-filter-gateway.yaml) for details).
- Ensure that you [have hardened your Kubernetes cluster](https://kubernetes.io/docs/concepts/security/security-checklist/).
- Ensure you have a proper upgrade/patch management process in place to apply security fixes to images and deployments (or _manifests_) in a timely manner.

Depending on your environment, threat model, and compliance requirements, additional hardening steps may be necessary.

### Prerequisites

- For the specific Kubernetes version per release, consult the [release notes](https://github.com/kubeflow/community-distribution/releases).
- Our Kind script below will take care of installing continuously tested Kubernetes, Kustomize and Kubectl versions for you.
- We use Kind as default but also support Minikube, Rancher, EKS, AKS, and GKE. GKE might need tiny adjustments documented here in this file and OpenShift is also possible.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ spec:
configMapKeyRef:
name: config
key: ISTIO_HOST
- name: ISTIO_USE_NOTEBOOK_SUBDOMAINS
Comment thread
sven-ernw marked this conversation as resolved.
Comment thread
sven-ernw marked this conversation as resolved.
valueFrom:
configMapKeyRef:
name: config
key: ISTIO_USE_NOTEBOOK_SUBDOMAINS
- name: ISTIO_HOST_NOTEBOOK
valueFrom:
configMapKeyRef:
name: config
key: ISTIO_HOST_NOTEBOOK
- name: ISTIO_HOST_AUTH
valueFrom:
configMapKeyRef:
name: config
key: ISTIO_HOST_AUTH
- name: ISTIO_AUTH_PATH
valueFrom:
configMapKeyRef:
name: config
key: ISTIO_AUTH_PATH
- name: CLUSTER_DOMAIN
valueFrom:
configMapKeyRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ CLUSTER_DOMAIN=cluster.local
ENABLE_CULLING=false
CULL_IDLE_TIME=1440
IDLENESS_CHECK_PERIOD=1
# Notebook multi-domain setup is disabled by default. Change the following variables to enable it:
Comment thread
sven-ernw marked this conversation as resolved.
Comment thread
sven-ernw marked this conversation as resolved.
ISTIO_USE_NOTEBOOK_SUBDOMAINS=false
ISTIO_HOST_NOTEBOOK=
ISTIO_HOST_AUTH=
ISTIO_AUTH_PATH=
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# This EnvoyFilter removes the cookie oauth2_proxy_kubeflow
# before the request is forwarded to the backend systems.
# This prevents token stealing:
# Otherwise, the bearer token would be leaked to the notebook's containers
# which would allow a contributor to access another contributor's token.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: gateway-remove-kubeflow-cookie
namespace: istio-system # Deployed in the gateway's namespace
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_request(request_handle)
local cookie_header = request_handle:headers():get("cookie")

if cookie_header then
Comment thread
sven-ernw marked this conversation as resolved.
local target_cookie = "oauth2_proxy_kubeflow"

-- Prefix the header so every cookie has an explicit boundary.
local new_cookie = string.gsub(";" .. cookie_header, ";%s*" .. target_cookie .. "=[^;]*", "")
new_cookie = string.gsub(new_cookie, "^;", "")
Comment on lines +38 to +40

-- Clean up any dangling semicolons or whitespace
new_cookie = string.gsub(new_cookie, "^[;%s]+", "")
new_cookie = string.gsub(new_cookie, "[;%s]+$", "")

if new_cookie == "" then
request_handle:headers():remove("cookie")
else
request_handle:headers():replace("cookie", new_cookie)
end
end
end

Check failure on line 52 in common/istio/istio-install/overlays/oauth2-proxy/envoy-filter-gateway.yaml

View workflow job for this annotation

GitHub Actions / format_YAML_files

52:18 [new-line-at-end-of-file] no new line character at the end of file
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ kind: Kustomization

resources:
- ../../base
- envoy-filter-gateway.yaml

components:
- ../../../../oauth2-proxy/components/istio-external-auth-patches
2 changes: 2 additions & 0 deletions common/oauth2-proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ data:
skip_provider_button = true
set_authorization_header = true
set_xauthrequest = true

# If you change the cookie_name, please ensure that you change the target_cookie name in common/istio/istio-install/overlays/oauth2-proxy/envoy-filter-gateway.yaml, too
cookie_name = "oauth2_proxy_kubeflow"
cookie_expire = "24h"
cookie_refresh = "59m" # This improves the user experience a lot
Expand Down
3 changes: 3 additions & 0 deletions common/oauth2-proxy/base/oauth2_proxy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ set_authorization_header = true
# may have other services that use standard auth headers.
set_xauthrequest = true

# If you change the cookie_name, please ensure that you change the target_cookie name in common/istio/istio-install/overlays/oauth2-proxy/envoy-filter-gateway.yaml, too
cookie_name = "oauth2_proxy_kubeflow"
# enable this setting for multi-domain notebook support:
# cookie_domains = [ "kubeflow.example.com" ]

# Dex default cookie expiration is 24h.
# If set to 168h (default oauth2-proxy), Istio will not be able to use the JWT after 24h,
Expand Down
134 changes: 134 additions & 0 deletions proposals/20260705-secure-notebook-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Secure Notebook Setup

Authors: Lorin Lehawany (@lorinl), Sven Nobis (@SvenTo)

## Goal/Motivation

These features add support for running notebooks on their own subdomains. This prevents session hijacking through a malicious notebook. It is recommended for production setups.

## Description

The multi-domain setup is recommended for a production Kubeflow deployment because the default setup allows an authenticated attacker to hijack sessions. However, because the setup has prerequisites and is not suitable for local development environments, it cannot be enabled by default.

This setup hosts the Kubeflow dashboard and APIs on a separate domain from the notebooks to prevent session hijacking from malicious notebooks through the user’s agent (browser). If an attacker hosts malicious notebooks and convinces a victim to visit the notebook’s URL, the attacker cannot steal session data or make API requests in the victim’s name.

## Prerequisite

If you want to enable the multi-domain setup, you need to meet the following prerequisites:

- A wildcard domain for Kubeflow or some kind of automated external domain management for the notebook domains (e.g., [ExternalDNS](https://github.com/kubernetes-sigs/external-dns)).
- A TLS certificate that covers both the Kubeflow dashboard domain and the wildcard notebook subdomains (for example, `kubeflow.example.org` and `*.kubeflow.example.org`), or some kind of automated certificate management for the notebook domains (e.g., [cert manager](https://cert-manager.io/docs/)).

This includes that Kubeflow is exposed externally (which is most likely given in a production environment):

- Istio ingress is exposed externally (required for subdomain routing).
- OAuth2 Proxy and Dex are exposed externally.

For instance, a minimal configuration to expose Kubeflow on an external domain requires the following settings:

**OAuth2/Dex**

The internal cluster Dex URLs should be replaced with the external Kubeflow ingress URL for OIDC issuer, token redemption, and JWKS endpoints in [``common/oauth2-proxy/base/oauth2_proxy.cfg``](../common/oauth2-proxy/base/oauth2_proxy.cfg). This example uses ``kubeflow.example.org`` as the external domain:

```sh
oidc_issuer_url = "https://kubeflow.example.org/dex"
redeem_url = "https://kubeflow.example.org/dex/token"
oidc_jwks_url = "https://kubeflow.example.org/dex/keys"
```

As well as the JWT issuer in the file [``common/oauth2-proxy/components/istio-external-auth/requestauthentication.dex-jwt.yaml``](../common/oauth2-proxy/components/istio-external-auth/requestauthentication.dex-jwt.yaml):

```sh
jwtRules:
- issuer: https://kubeflow.example.org/dex
```

As well as the JWT issuer in the dex configuration file [``common/dex/overlays/oauth2-proxy/config-map.yaml``](../common/dex/overlays/oauth2-proxy/config-map.yaml):

```sh
data:
config.yaml: |
issuer: https://kubeflow.example.org/dex
```

Secondly, the Kubeflow Ingress Gateway needs to be exposed via HTTPS:

**Istio Service**

The Istio service needs to be exposed to the outside. Change the service type to ``LoadBalancer`` in the file [`common/istio/istio-install/base/patches/service.yaml`](../common/istio/istio-install/base/patches/service.yaml):

```yaml
apiVersion: v1
kind: Service
metadata:
name: istio-ingressgateway
namespace: istio-system
spec:
type: LoadBalancer
```

**Kubeflow Gateway**

The Kubeflow gateway should enable HTTPS, and a TLS certificate needs to be referenced in the file [`common/istio/kubeflow-istio-resources/base/kf-istio-resources.yaml`](../common/istio/kubeflow-istio-resources/base/kf-istio-resources.yaml):
Comment thread
sven-ernw marked this conversation as resolved.

```yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: kubeflow-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "*"
tls:
mode: SIMPLE
credentialName: https-credential # set this to the secret with the wildcard TLS certificate and key
```

This will make the setup work. Please ensure that you follow the recommendations in the [_Security Considerations_ section](../README.md#security-considerations) for guidance on a secure setup.

## Implementation details to enable multi-domain setup

The list below shows all steps required to enable the multi-domain setup and shows how to configure them.

The notebook subdomains must be part of the Kubeflow authentication authority. In a default setup, this means that the notebook domain is a subdomain of the Kubeflow dashboard. Otherwise, the setup will not work. For instance, if the dashboard is hosted on ``kubeflow.example.org``, every Notebook in the `example` profile uses the host `example-notebook.kubeflow.example.org`, when `ISTIO_HOST_NOTEBOOK` is set to `${NAMESPACE}-notebook.kubeflow.example.org`.

**Environment parameters**

The following parameters need to be defined in the configuration file [`applications/notebooks-v1/upstream/notebook-controller/manager/params.env`](../applications/notebooks-v1/upstream/notebook-controller/manager/params.env):

| Parameter | Description |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ISTIO_USE_NOTEBOOK_SUBDOMAINS` | Set this value to ``true``. |
| `ISTIO_HOST_NOTEBOOK` | Domain template used by Istio to host notebooks (e.g., `${NAMESPACE}-notebook.kubeflow.example.org`). `${NAMESPACE}` will be replaced with the Notebook's namespace (Kubeflow profile). |
| `ISTIO_HOST_AUTH` | Host used by Istio for handling authentication callbacks or login flows (e.g., `kubeflow.example.org`). |
| `ISTIO_AUTH_PATH` | Optional, defaults to `/oauth2/`; Can be used to change the base URL path used by Istio for authentication callbacks or login flows (e.g. `/oauth2/`). |
Comment on lines +114 to +117
| | This path must match the routing configured in the authentication provider (e.g., OAuth2 Proxy) so that login and callback requests are correctly handled. |

**Cookie domains**

Enable this setting for multi-domain notebook support in the configuration file [`common/oauth2-proxy/base/oauth2_proxy.cfg`](../common/oauth2-proxy/base/oauth2_proxy.cfg):

```sh
cookie_domains = [ "kubeflow.example.org" ]
```

## Does this break any existing functionality?

The multi-domain setup is not enabled by default and thus this change will not change any default behavior. It should not break any existing functionality if enabled, too.

## Does this solve any outstanding security issues?

Yes. This implementation addresses a security issue that could allow session hijacking via a malicious notebook; see [the GitHub security advisory](https://github.com/kubeflow/notebooks/security/advisories/GHSA-qjw6-hpc7-w36h) for details.
Loading