Add kubeflow/v1.10.0
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
# Kubeflow with oauth2-proxy and envoyExtAuthzHttp
|
||||
|
||||
For a quick install, see [Example installation](#example-installation).
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
Kubeflow authorization operates using custom authentication headers:
|
||||
* `kubeflow-userid`: Contains the user's email address.
|
||||
* `kubeflow-groups`: Holds a comma-separated list of user groups.
|
||||
* Note: The functionality for `kubeflow-groups` is not fully operational at this time.
|
||||
|
||||
This feature was implemented using a custom, minimalistic authorization tool from Arrikto
|
||||
named `oidc-authservice`. This tool was integrated into Istio using `EnvoyFilter`.
|
||||
|
||||
The adoption of `envoyExtAuthzHttp` for authentication offers several advantages:
|
||||
* **Simplified Authorization Process**: `envoyExtAuthzHttp` extension streamlines adding
|
||||
external authorization to the Envoy proxy within an Istio service mesh. It allows for
|
||||
declarative policy configuration, reducing the complexity associated with direct
|
||||
`EnvoyFilter` modifications.
|
||||
* **Standardization**: Istio recommends `envoyExtAuthzHttp` for its standardized approach.
|
||||
This promotes consistency across Istio deployments and simplifies understanding and
|
||||
maintenance of the authorization logic.
|
||||
* **Separate Policy Management**: Authorization policies are defined in distinct
|
||||
configuration resources, not directly in `EnvoyFilter`. This separation eases policy
|
||||
management and facilitates updates or replacements of authorization logic without
|
||||
altering `EnvoyFilter` configurations.
|
||||
* **Seamless Integration with Istio**: `envoyExtAuthzHttp` harmonizes with Istio features
|
||||
like `AuthorizationPolicy` and `VirtualService`, enabling smoother integration within
|
||||
Istio's ecosystem and taking advantage of its architecture and capabilities.
|
||||
* **Future-Proofing**: There is a high likelihood that Kubeflow's internal authentication
|
||||
decisions will transition to relying directly on JWTs instead of custom auth headers.
|
||||
|
||||
Additional information on the benefits of moving away from `EnvoyFilter` can be found in these
|
||||
resources:
|
||||
* [Istio GitHub Issue #27790](https://github.com/istio/istio/issues/27790)
|
||||
* [Istio Documentation on Authorization with Custom Authentication](https://istio.io/latest/docs/tasks/security/authorization/authz-custom/)
|
||||
|
||||
While `envoyExtAuthzHttp` could potentially integrate with `oidc-authservice`, `oauth2-proxy`
|
||||
emerges as a more advanced authentication proxy. It boasts broader community support and is
|
||||
widely used in the industry, including in the official Istio documentation on [External
|
||||
Authorization](https://istio.io/latest/docs/tasks/security/authorization/authz-custom).
|
||||
|
||||
For more details on the `oauth2-proxy`, refer to the [official documentation](https://oauth2-proxy.github.io/oauth2-proxy/docs/behaviour).
|
||||
|
||||
## Available Components
|
||||
|
||||
Below is a list of the available Kustomize Components with brief descriptions. Click on each for more details.
|
||||
|
||||
* **[allow-unauthenticated-issuer-discovery](./allow-unauthenticated-issuer-discovery.md)** -
|
||||
Creates a ClusterRoleBinding for anonymous access to Kubernetes OIDC
|
||||
discovery.
|
||||
|
||||
* **[central-dashboard](./central-dashboard.md)** - Configures the central
|
||||
dashboard to use oauth2-proxy logout URL.
|
||||
|
||||
* **[istio-external-auth](./istio-external-auth.md)** - Modifies Istio
|
||||
configuration to define oauth2-proxy as external authentication middleware via
|
||||
envoyExtAuthzHttp extension provider. Adds RequestAuthentication to trust Dex
|
||||
as IdP and AuthorizationPolicies to delegate authentication to oauth2-proxy.
|
||||
|
||||
* **[istio-m2m](./istio-m2m.md)** - Creates RequestAuthentication for Istio to
|
||||
trust the OIDC Issuer specified in parameters. This allows the generation of
|
||||
JWTs for authenticating requests, typically as Bearer Tokens in the
|
||||
Authorization header. By default, the OIDC Issuer is the in-cluster Kubernetes
|
||||
OIDC.
|
||||
|
||||
## CloudFlare
|
||||
|
||||
CloudFlare requires that certain static, standard web browser assets are accessible without
|
||||
user authentication. This is crucial because CloudFlare aims to cache these assets for
|
||||
enhanced performance. If these assets necessitate user authentication, CloudFlare robots
|
||||
will be redirected to the authentication page, potentially causing access issues with the
|
||||
Kubeflow instance behind CloudFlare.
|
||||
|
||||
This issue can be resolved by defining a set of assets in the Istio `AuthorizationPolicy`
|
||||
that do not require authentication. An example `AuthorizationPolicy` for this purpose is
|
||||
provided in the file `authorizationpolicy.istio-ingressgateway-oauth2-proxy.cloudflare.yaml`.
|
||||
|
||||
## Explaining the Auth Routine
|
||||
|
||||
1. Istio is configured with the `envoyExtAuthzHttp` extension provider pointing to the
|
||||
`oauth2-proxy` service. This configuration enables the use of this extension in
|
||||
`AuthorizationPolicy` for adding external authorization to the service mesh.
|
||||
2. The Istio service mesh has an `AuthorizationPolicy` named `istio-ingressgateway-oauth2-proxy`
|
||||
in the `istio-system` (Istio root) namespace. This policy is set with `action: CUSTOM` and
|
||||
specifies the `oauth2-proxy` provider. Consequently, every request to the
|
||||
`istio-ingressgateway` must pass through the external authorization service, `oauth2-proxy`.
|
||||
3. `oauth2-proxy` decides based on the cookie named `oauth2_proxy_kubeflow`. If this cookie
|
||||
is absent, expired, or invalid, `oauth2-proxy` redirects to the configured OIDC provider,
|
||||
typically `dex`. The authentication redirect includes:
|
||||
* A `redirect_uri` for redirecting the user post-authentication,
|
||||
* A code challenge to guard against interception and replay attacks,
|
||||
* A state parameter to validate the authorization response's authenticity and
|
||||
ensure it originates from the initial request.
|
||||
|
||||
Post-authentication, a cookie is set in the user's browser, used by Istio and `oauth2-proxy`
|
||||
for authorizing requests.
|
||||
|
||||
`oauth2-proxy` also checks for an `Authorization` header with a JWT bearer token. It trusts
|
||||
JWTs issued by the configured OIDC provider (default `dex`) and can be configured to trust
|
||||
additional JWTs. If a valid JWT is present, `oauth2-proxy` forwards the request to Istio
|
||||
along with the authorization header.
|
||||
|
||||
The key objective here is to supply an `Authorization` header with a JWT Bearer Token,
|
||||
later used in `RequestAuthentication`. This step configures Istio to trust the JWT, parse
|
||||
its claims to include user email and groups in custom Kubeflow authorization headers, and
|
||||
make routing and authorization decisions based on these JWT claims.
|
||||
4. With this setup, Istio always receives the JWT in requests, enabling authorization
|
||||
decisions based on JWT claims.
|
||||
|
||||
## Using HTTPS
|
||||
|
||||
`oauth2-proxy` is initially set up with an `http` endpoint, secured by the Istio Service Mesh.
|
||||
As a result, `oauth2-proxy` may default to assuming that the authentication redirect URI should
|
||||
also use `http`. To enforce the use of `https`, modify the variable `FORCE_HTTPS` in
|
||||
`kustomization.yaml` to `true`. This adjustment leverages the `oauth2-proxy` configuration
|
||||
option `--cookie-secure`, ensuring redirection occurs with `https`.
|
||||
|
||||
## Istio JWT Public Key Refresh Interval
|
||||
|
||||
In the initial setup of Kubeflow, it's common for `istiod` to become available before `dex`.
|
||||
Istio's `RequestAuthentication` is configured to retrieve the JWT Public Key from the Issuer
|
||||
URL. If the Issuer is not yet operational, placeholder keys are set, which can render the
|
||||
setup nonfunctional until Istio can access the correct JWT Public Key. To address this,
|
||||
`istiod` is configured with the environment variable `PILOT_JWT_PUB_KEY_REFRESH_INTERVAL="1m"`.
|
||||
This setting ensures the JWT Public Key is refreshed every minute, rather than the default
|
||||
20 minutes.
|
||||
|
||||
Without this configuration, users may encounter the following Istio error:
|
||||
```
|
||||
Jwks doesn't have key to match kid or alg from Jwt
|
||||
```
|
||||
|
||||
## Issues with This Setup
|
||||
|
||||
While not an inherent issue with Istio or `oauth2-proxy`, the current Kubeflow configuration
|
||||
automatically redirects to a URL specified in the logout response body's `afterLogoutURL` key.
|
||||
This behavior stems from custom integration with the `oidc-authservice` component. While
|
||||
`oauth2-proxy` is capable of redirecting to the base Kubeflow page, this custom setup results
|
||||
in users being logged out (with the authentication cookie removed) but not redirected back to
|
||||
the Kubeflow Home Page.
|
||||
|
||||
Details of this custom integration are available at:
|
||||
* [oidc-authservice server.go](https://github.com/arrikto/oidc-authservice/blob/0c4ea9a/server.go#L509)
|
||||
* [Kubeflow logout-button.js](https://github.com/kubeflow/kubeflow/blob/c6c4492/components/centraldashboard/public/components/logout-button.js#L50)
|
||||
|
||||
To log in again, users must manually refresh the page.
|
||||
|
||||
## Example Installation
|
||||
|
||||
To install Kubeflow configured to use `oauth2-proxy` with Istio's `envoyExtAuthzHttp` extension,
|
||||
make the following changes to the `example/kustomization.yaml` file:
|
||||
* use `oauth2-proxy` overlay for istio-install
|
||||
```
|
||||
# from
|
||||
- ../common/istio-1-24/istio-install/base
|
||||
# to
|
||||
- ../common/istio-1-24/istio-install/overlays/oauth2-proxy
|
||||
```
|
||||
* change `OIDC Authservice` to `oauth2-proxy for OIDC` and use overlay for m2m
|
||||
bearer tokens with self-signed in-cluster issuer
|
||||
```
|
||||
# from
|
||||
- ../common//oidc-authservice/base
|
||||
# to
|
||||
- ../common/oauth2-proxy/overlays/m2m-dex-and-kind
|
||||
```
|
||||
* change Dex overlay
|
||||
```
|
||||
# from
|
||||
- ../common/dex/overlays/istio
|
||||
# to
|
||||
- ../common/dex/overlays/oauth2-proxy
|
||||
* change Central Dashboard overlay to use oauth2-proxy for logout
|
||||
```
|
||||
# from
|
||||
- ../apps/centraldashboard/upstream/overlays/kserve
|
||||
# to
|
||||
- ../apps/centraldashboard/manuel-patches/overlays/oauth2-proxy
|
||||
```
|
||||
|
||||
All those changes combined can be done with this single command:
|
||||
```diff
|
||||
$ git apply <<EOF
|
||||
diff --git a/example/kustomization.yaml b/example/kustomization.yaml
|
||||
index c1a85789..4a50440c 100644
|
||||
--- a/example/kustomization.yaml
|
||||
+++ b/example/kustomization.yaml
|
||||
@@ -38,11 +38,11 @@ resources:
|
||||
# Istio
|
||||
- ../common/istio-1-24/istio-crds/base
|
||||
- ../common/istio-1-24/istio-namespace/base
|
||||
-- ../common/istio-1-24/istio-install/base
|
||||
-# OIDC Authservice
|
||||
-- ../common//oidc-authservice/base
|
||||
+- ../common/istio-1-24/istio-install/overlays/oauth2-proxy
|
||||
+# oauth2-proxy for OIDC
|
||||
+- ../common/oauth2-proxy/overlays/m2m-dex-and-kind
|
||||
# Dex
|
||||
-- ../common/dex/overlays/istio
|
||||
+- ../common/dex/overlays/oauth2-proxy
|
||||
# KNative
|
||||
- ../common/knative/knative-serving/overlays/gateways
|
||||
- ../common/knative/knative-eventing/base
|
||||
@@ -60,7 +60,7 @@ resources:
|
||||
# Katib
|
||||
- ../apps/katib/upstream/installs/katib-with-kubeflow
|
||||
# Central Dashboard
|
||||
-- ../apps/centraldashboard/upstream/overlays/kserve
|
||||
+- ../apps/centraldashboard/overlays
|
||||
# Admission Webhook
|
||||
- ../apps/admission-webhook/upstream/overlays/cert-manager
|
||||
# Jupyter Web App
|
||||
EOF
|
||||
```
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
# Unauthenticated Issuer Discovery
|
||||
|
||||
If you are using Kubernetes with tools like kind, vCluster, minikube, or similar solutions for local
|
||||
development, it's highly likely that the Kubernetes OIDC Issuer operates within the cluster and is
|
||||
secured with self-signed certificates.
|
||||
|
||||
To facilitate the use of m2m tokens with `oauth2-proxy` and Istio, both tools must perform OIDC
|
||||
Connect Discovery on the Token Issuer. Kubernetes offers OIDC Discovery functionality at a specific
|
||||
URI:
|
||||
```
|
||||
https://kubernetes.default.svc.cluster.local/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
Access to this endpoint is blocked by default due to RBAC policies, but it can be enabled by
|
||||
creating a `ClusterRoleBinding`. This binding associates the predefined `ClusterRole`
|
||||
`system:service-account-issuer-discovery` with the `system:unauthenticated` group. The
|
||||
configuration for this is detailed in the resource file `clusterrolebinding.unauthenticated-oidc-viewer.yaml`.
|
||||
|
||||
Once this step is completed, the endpoint can be accessed to reveal the Issuer URL:
|
||||
```bash
|
||||
$ curl -k https://kubernetes.default.svc.cluster.local/.well-known/openid-configuration
|
||||
|
||||
# Example output in kind:
|
||||
{"issuer":"https://kubernetes.default.svc.cluster.local","jwks_uri":"https://172.18.0.5:6443/openid/v1/jwks","response_types_supported":["id_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"]}
|
||||
|
||||
# Example output in vCluster:
|
||||
{"issuer":"https://kubernetes.default.svc.cluster.local","jwks_uri":"https://1.2.3.4:6443/openid/v1/jwks","response_types_supported":["id_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"]}
|
||||
|
||||
# Example output in AWS EKS:
|
||||
{"issuer":"https://oidc.eks.region.amazonaws.com/id/123abc","jwks_uri":"https://ip-1-2-3-4.eu-central-1.compute.internal:443/openid/v1/jwks","response_types_supported":["id_token"],"subject_types_supported":["public"],"id_token_signing_alg_values_supported":["RS256"]}
|
||||
```
|
||||
|
||||
If you're operating in a `vCluster`, access to the endpoint specified under `jwks_uri` (for example,
|
||||
`https://1.2.3.4:6443/openid/v1/jwks`) is managed separately, and merely creating the previously
|
||||
mentioned `ClusterRoleBinding` is insufficient. To circumvent this limitation, you can configure the
|
||||
`kube-apiserver` to allow anonymous authentication by setting `--anonymous-auth=true`. This is
|
||||
achieved by appending `--kube-apiserver-arg=anonymous-auth=true` to the list of arguments in the
|
||||
Helm Chart Values file:
|
||||
```yaml
|
||||
vcluster:
|
||||
extraArgs:
|
||||
- --kube-apiserver-arg=anonymous-auth=true
|
||||
```
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: unauthenticated-oidc-viewer
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: system:service-account-issuer-discovery
|
||||
subjects:
|
||||
- apiGroup: rbac.authorization.k8s.io
|
||||
kind: Group
|
||||
name: system:unauthenticated
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
resources:
|
||||
- clusterrolebinding.unauthenticated-oidc-viewer.yaml
|
||||
@@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
patches:
|
||||
- path: patches/deployment.logout-url.yaml
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: centraldashboard
|
||||
namespace: kubeflow
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: centraldashboard
|
||||
env:
|
||||
# This successfully logs out the user but the user is not redirected to
|
||||
# the home page.
|
||||
# https://github.com/kubeflow/kubeflow/blob/c6c4492/components/centraldashboard/public/components/logout-button.js#L50
|
||||
# Please refresh the page after logging out.
|
||||
- name: LOGOUT_URL
|
||||
value: /oauth2/sign_out
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
# the default JWKS endpoint for Kind is not public, and uses a self-signed certificate
|
||||
# for the Istio RequestAuthentication to trust it, we need to proxy the cluster's JWKS endpoint over HTTP
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: cluster-jwks-proxy
|
||||
namespace: istio-system
|
||||
labels:
|
||||
app.kubernetes.io/name: cluster-jwks-proxy
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: cluster-jwks-proxy
|
||||
namespace: istio-system
|
||||
labels:
|
||||
app.kubernetes.io/name: cluster-jwks-proxy
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
selector:
|
||||
app.kubernetes.io/name: cluster-jwks-proxy
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cluster-jwks-proxy
|
||||
namespace: istio-system
|
||||
labels:
|
||||
app.kubernetes.io/name: cluster-jwks-proxy
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: cluster-jwks-proxy
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: cluster-jwks-proxy
|
||||
spec:
|
||||
serviceAccountName: cluster-jwks-proxy
|
||||
containers:
|
||||
- name: kubectl-proxy
|
||||
image: docker.io/bitnami/kubectl
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
startupProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 2
|
||||
httpGet:
|
||||
path: /openid/v1/jwks
|
||||
port: http
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
httpGet:
|
||||
path: /openid/v1/jwks
|
||||
port: http
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
httpGet:
|
||||
path: /openid/v1/jwks
|
||||
port: http
|
||||
args:
|
||||
- proxy
|
||||
- --address=0.0.0.0
|
||||
- --port=8080
|
||||
## accept all hosts (default is local only)
|
||||
- --accept-hosts=.*
|
||||
## only accept requests to '/openid/v1/jwks' and '/.well-known/openid-configuration'
|
||||
- --accept-paths=^(?:/openid/v1/jwks)|(?:/.well-known/openid-configuration)$
|
||||
## reject all methods except 'GET'
|
||||
- --reject-methods=^(POST|PUT|PATCH|DELETE|HEAD|OPTIONS|CONNECT|TRACE)$
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
resources:
|
||||
- cluster-jwks-proxy.yaml
|
||||
|
||||
images:
|
||||
- name: docker.io/bitnami/kubectl
|
||||
newName: docker.io/bitnami/kubectl
|
||||
newTag: 1.30.4
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
patches:
|
||||
- path: patches/cm.enable-oauth2-proxy.yaml
|
||||
- path: patches/deployment.jwt-refresh-interval.yaml
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: istio
|
||||
namespace: istio-system
|
||||
data:
|
||||
mesh: |-
|
||||
accessLogFile: /dev/stdout
|
||||
defaultConfig:
|
||||
discoveryAddress: istiod.istio-system.svc:15012
|
||||
proxyMetadata: {}
|
||||
tracing: {}
|
||||
enablePrometheusMerge: true
|
||||
rootNamespace: istio-system
|
||||
tcpKeepalive:
|
||||
interval: 5s
|
||||
probes: 3
|
||||
time: 10s
|
||||
trustDomain: cluster.local
|
||||
extensionProviders:
|
||||
- envoyExtAuthzHttp:
|
||||
headersToDownstreamOnDeny:
|
||||
- content-type
|
||||
- set-cookie
|
||||
headersToUpstreamOnAllow:
|
||||
- authorization
|
||||
- path
|
||||
- x-auth-request-email
|
||||
- x-auth-request-groups
|
||||
- x-auth-request-user
|
||||
includeRequestHeadersInCheck:
|
||||
- authorization
|
||||
- cookie
|
||||
service: oauth2-proxy.oauth2-proxy.svc.cluster.local
|
||||
port: 80
|
||||
name: oauth2-proxy
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: istiod
|
||||
namespace: istio-system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: discovery
|
||||
env:
|
||||
# Istio will refresh the JWT Public Keys provided with
|
||||
# RequestAuthentication by default every 20 minutes. For deployment
|
||||
# from scratch this is not ideal because there is a high chance that
|
||||
# the istiod will be available before dex is available, triggering
|
||||
# Istio mechanism to use a placeholder jwt until refreshed.
|
||||
- name: PILOT_JWT_PUB_KEY_REFRESH_INTERVAL
|
||||
value: "1m"
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: AuthorizationPolicy
|
||||
metadata:
|
||||
name: istio-ingressgateway-oauth2-proxy
|
||||
namespace: istio-system
|
||||
spec:
|
||||
action: CUSTOM
|
||||
provider:
|
||||
name: oauth2-proxy
|
||||
selector:
|
||||
matchLabels:
|
||||
app: istio-ingressgateway
|
||||
rules:
|
||||
# We ONLY authenticate requests that DON'T have an `Authorization` header using oauth2-proxy.
|
||||
# This is because we use RequestAuthentication to authenticate requests with an `Authorization` header.
|
||||
- when:
|
||||
- key: request.headers[authorization]
|
||||
notValues: ["*"]
|
||||
to:
|
||||
- operation:
|
||||
notPaths:
|
||||
# Exclude dex paths, otherwise users won't be able to log in.
|
||||
- /dex/*
|
||||
- /dex/**
|
||||
- /oauth2/*
|
||||
|
||||
# Exclude paths which are safe to cache by Cloudflare.
|
||||
- /favicon*
|
||||
- /webcomponentsjs*
|
||||
- /vendor.bundle.js
|
||||
- /app.bundle.js
|
||||
- /dashboard_lib.bundle.js
|
||||
- /assets*
|
||||
- /app.css
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: AuthorizationPolicy
|
||||
metadata:
|
||||
name: istio-ingressgateway-oauth2-proxy
|
||||
namespace: istio-system
|
||||
spec:
|
||||
action: CUSTOM
|
||||
provider:
|
||||
name: oauth2-proxy
|
||||
selector:
|
||||
matchLabels:
|
||||
app: istio-ingressgateway
|
||||
rules:
|
||||
# We ONLY authenticate requests that DON'T have an `Authorization` header using oauth2-proxy.
|
||||
# This is because we use RequestAuthentication to authenticate requests with an `Authorization` header.
|
||||
- when:
|
||||
- key: request.headers[authorization]
|
||||
notValues: ["*"]
|
||||
to:
|
||||
- operation:
|
||||
notPaths:
|
||||
# Exclude dex paths, otherwise users won't be able to log in.
|
||||
- /dex/*
|
||||
- /dex/**
|
||||
- /oauth2/*
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: AuthorizationPolicy
|
||||
metadata:
|
||||
name: istio-ingressgateway-require-jwt
|
||||
namespace: istio-system
|
||||
spec:
|
||||
action: DENY
|
||||
selector:
|
||||
matchLabels:
|
||||
app: istio-ingressgateway
|
||||
rules:
|
||||
# Deny requests that don't have a verified JWT (from a RequestAuthentication)
|
||||
# Note, even user requests that have been authenticated by oauth2-proxy will have a JWT,
|
||||
# because oauth2-proxy injects a Dex JWT into the request.
|
||||
- from:
|
||||
- source:
|
||||
notRequestPrincipals: ["*"]
|
||||
to:
|
||||
- operation:
|
||||
notPaths:
|
||||
# Exclude dex paths, otherwise users won't be able to log in.
|
||||
- /dex/*
|
||||
- /dex/**
|
||||
- /oauth2/*
|
||||
|
||||
# Exclude paths which are safe to cache by Cloudflare.
|
||||
- /favicon*
|
||||
- /webcomponentsjs*
|
||||
- /vendor.bundle.js
|
||||
- /app.bundle.js
|
||||
- /dashboard_lib.bundle.js
|
||||
- /assets*
|
||||
- /app.css
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: AuthorizationPolicy
|
||||
metadata:
|
||||
name: istio-ingressgateway-require-jwt
|
||||
namespace: istio-system
|
||||
spec:
|
||||
action: DENY
|
||||
selector:
|
||||
matchLabels:
|
||||
app: istio-ingressgateway
|
||||
rules:
|
||||
# Deny requests that don't have a verified JWT (from a RequestAuthentication)
|
||||
# Note, even user requests that have been authenticated by oauth2-proxy will have a JWT,
|
||||
# because oauth2-proxy injects a Dex JWT into the request.
|
||||
- from:
|
||||
- source:
|
||||
notRequestPrincipals: ["*"]
|
||||
to:
|
||||
- operation:
|
||||
notPaths:
|
||||
# Exclude dex paths, otherwise users won't be able to log in.
|
||||
- /dex/*
|
||||
- /dex/**
|
||||
- /oauth2/*
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
resources:
|
||||
- authorizationpolicy.istio-ingressgateway-oauth2-proxy.yaml
|
||||
- authorizationpolicy.istio-ingressgateway-require-jwt.yaml
|
||||
- requestauthentication.dex-jwt.yaml
|
||||
|
||||
# If want to enable caching for some paths (e.g. when using Cloudflare),
|
||||
# use the following AuthorizationPolicies instead of the default ones.
|
||||
#- authorizationpolicy.istio-ingressgateway-oauth2-proxy.cloudflare.yaml
|
||||
#- authorizationpolicy.istio-ingressgateway-require-jwt.cloudflare.yaml
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: RequestAuthentication
|
||||
metadata:
|
||||
name: dex-jwt
|
||||
namespace: istio-system
|
||||
spec:
|
||||
# we only apply to the ingress-gateway because:
|
||||
# - there is no need to verify the same tokens at each sidecar
|
||||
# - having no selector will apply to the RequestAuthentication to ALL
|
||||
# Pods in the mesh, even ones which are not part of Kubeflow
|
||||
# - some Kubeflow services accept direct connections with Kubernetes JWTs,
|
||||
# and we don't want to require that users configure Istio to verify Kubernetes JWTs
|
||||
# as there is no method to do this which works on all distributions.
|
||||
selector:
|
||||
matchLabels:
|
||||
app: istio-ingressgateway
|
||||
|
||||
jwtRules:
|
||||
- issuer: http://dex.auth.svc.cluster.local:5556/dex
|
||||
|
||||
# `forwardOriginalToken` is not strictly required to be true.
|
||||
# there are pros and cons to each value:
|
||||
# - true: the original token is forwarded to the destination service
|
||||
# which raises the risk of the token leaking
|
||||
# - false: the original token is stripped from the request
|
||||
# which will prevent the destination service from
|
||||
# verifying the token (possibly with its own RequestAuthentication)
|
||||
forwardOriginalToken: true
|
||||
|
||||
# This will unpack the JWTs issued by dex into the expected headers.
|
||||
# It is applied to BOTH the m2m tokens from outside the cluster (which skip
|
||||
# oauth2-proxy because they already have a dex JWT), AND user requests which were
|
||||
# authenticated by oauth2-proxy (which injected a dex JWT).
|
||||
outputClaimToHeaders:
|
||||
- header: kubeflow-userid
|
||||
claim: email
|
||||
- header: kubeflow-groups
|
||||
claim: groups
|
||||
|
||||
# We explicitly set `fromHeaders` to ensure that the JWT is only extracted from the `Authorization` header.
|
||||
# This is because we exclude requests that have an `Authorization` header from oauth2-proxy.
|
||||
fromHeaders:
|
||||
- name: Authorization
|
||||
prefix: "Bearer "
|
||||
@@ -0,0 +1,13 @@
|
||||
# Kubernetes M2M Authentication with Istio and RequestAuthentication
|
||||
|
||||
## Overview
|
||||
|
||||
This kustomize component enables M2M (Machine-to-Machine) authentication in Kubernetes, using
|
||||
Istio and the `RequestAuthentication` object. It configures Istio to trust JWTs (JSON Web Tokens)
|
||||
in Authorization Bearer tokens when the JWT issuer matches the one in `RequestAuthentication`. The
|
||||
default setup uses Kubernetes' self-served OIDC issuer with self-signed certificates.
|
||||
|
||||
In Kubernetes clusters managed by platform providers, the OIDC issuer is usually managed by the
|
||||
provider and served behind publicly trusted certificates. In these cases, it's advisable to use
|
||||
the platform-managed Kubernetes OIDC issuer in the `RequestAuthentication` for seamless integration
|
||||
and authentication compliance with the platform's security standards.
|
||||
@@ -0,0 +1,5 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1alpha1
|
||||
kind: Component
|
||||
|
||||
resources:
|
||||
- requestauthentication.yaml
|
||||
@@ -0,0 +1,42 @@
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: RequestAuthentication
|
||||
metadata:
|
||||
name: m2m-token-issuer
|
||||
namespace: istio-system
|
||||
spec:
|
||||
# we only apply to the ingress-gateway because:
|
||||
# - there is no need to verify the same tokens at each sidecar
|
||||
# - having no selector will apply the RequestAuthentication to ALL
|
||||
# Pods in the mesh, even ones which are not part of Kubeflow
|
||||
selector:
|
||||
matchLabels:
|
||||
app: istio-ingressgateway
|
||||
|
||||
jwtRules:
|
||||
- # The `issuer` must be replaced with a Kustomize patch.
|
||||
issuer: PATCH_ME
|
||||
|
||||
# `forwardOriginalToken` is not strictly required to be true.
|
||||
# there are pros and cons to each value:
|
||||
# - true: the original token is forwarded to the destination service
|
||||
# which raises the risk of the token leaking
|
||||
# - false: the original token is stripped from the request
|
||||
# which will prevent the destination service from
|
||||
# verifying the token (possibly with its own RequestAuthentication)
|
||||
forwardOriginalToken: true
|
||||
|
||||
# This will unpack the JWTs issued by Kubernetes into the expected headers.
|
||||
outputClaimToHeaders:
|
||||
- header: kubeflow-userid
|
||||
claim: sub
|
||||
- # NOTE: K8S SA Tokens (e.g. those created with `kubectl create token`) do not contain a `groups` claim,
|
||||
# but we need to ensure that any groups header provided by the request is overwritten to avoid
|
||||
# users passing a valid JWT with `kubeflow-groups` header to impersonate other users.
|
||||
header: kubeflow-groups
|
||||
claim: groups
|
||||
|
||||
# We explicitly set `fromHeaders` to ensure that the JWT is only extracted from the `Authorization` header.
|
||||
# This is because we exclude requests that have an `Authorization` header from oauth2-proxy.
|
||||
fromHeaders:
|
||||
- name: Authorization
|
||||
prefix: "Bearer "
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 636 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 23 KiB |
Reference in New Issue
Block a user