Skip to content

Commit bc0e163

Browse files
committed
docs/proposal: submit poll based binding
1 parent 0644b16 commit bc0e163

3 files changed

Lines changed: 228 additions & 0 deletions

File tree

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
---
2+
type: proposal
3+
title: Global / Federated Rules API
4+
status: in-progress
5+
owner: s-urbaniak
6+
---
7+
8+
* **Owners:**
9+
* @s-urbaniak
10+
11+
* **Related Tickets:**
12+
* N/A
13+
14+
## Summary
15+
16+
kube-bind offers a user-friendly approach of being able to bind API resources provided by an external party using a simple URL. This URL can be invoked directly via the terminal and the rest of the binding process is finalized in a user web browser session.
17+
18+
At the end a local callback ensures that the necessary metadata of the binding process is passed back to the kubectl `bind` process.
19+
20+
While being user-friendly the current approach has a couple of drawbacks. An alternative method is described which adds a new "polling" based approach vs. the current "callback" based approach.
21+
22+
## Why
23+
24+
kube-bind allows to bind APIs offered by providers using a URL passed to the `bind` subcommand.
25+
As part of the binding process the following steps are executed:
26+
27+
1. The kubectl `bind` plugin retrieves provider metadata
28+
which includes information about supported authentication methods at the provider.
29+
Currently, OAuth 2 code grant flow is supported.
30+
2. The kubectl `bind` renders an authentication URL on the terminal,
31+
augmented with additional session data.
32+
3. The user executes the rendered URL link
33+
and finalizes authentication and API selection in his local browser.
34+
35+
kubectl `bind` plugin blocks until authentication and API selection is finalized.
36+
Currently, this is accomplished using a localhost web server listening on an ephemeral local port on the user machine.
37+
38+
After the end of the above process the kube-bind backend invokes an HTTP 302 localhost redirect in the user browser session. The callback URL includes a serialized `kubebindv1alpha1.BindingResponse` JSON object. This object is passed as a base64 encoded `response` parameter which is added to the callback localhost URL as a query parameter.
39+
40+
The following figure illustrates the current process:
41+
42+
![](localhost-callback.png)
43+
Link: https://whimsical.com/kube-bind-auth-flow-FYCNPvj5m27pKUDVYxVRGy
44+
45+
The current solution has a couple of drawbacks:
46+
47+
1. The kubectl `bind` plugin starts localhost a web server running on the user machine. This makes it currently impossible to use kubectl `bind` on a remote machine i.e. via an SSH session.
48+
49+
2. The serialized encoded length of the `kubebindv1alpha1.BindingResponse` is currently passed as a URL parameter which should not exceed ~2000 characters in most web browser implementations. Worse, this upper bound is not standardized. Finally, passing large URL parameters is not recommended.
50+
51+
The current method will be called as "callback based" approach in the remainder of this proposal.
52+
53+
## Goals
54+
55+
1. **MUST** enable the possibility to use kubectl `bind` on a remote machine i.e. via an SSH session.
56+
2. **MUST** remove the necessity to start a localhost web server on the user machine.
57+
3. **MUST** remove the limitation of encoding the binding response object via a URL query parameter.
58+
4. **MUST** retain user-friendliness of invoking a single URL to bind external APIs.
59+
60+
## How
61+
62+
### kubectl `bind`
63+
64+
Next to the above describe "callback based" approach kubectl `bind` additionally supports a "polling" based approach.
65+
66+
Instead of having a localhost web server blocking until a callback http request is executed by the user web browser session, the kubectl `bind` process regularly polls the kube-bind backend whether the authentication and API resource selection process is finalized.
67+
68+
As a result, the kubectl `bind` process downloads the `kubebindv1alpha1.BindingResponse` JSON object directly from the polled URL.
69+
70+
Here, the following steps are executed:
71+
72+
1. The kubectl `bind` plugin retrieves provider metadata
73+
which includes information about supported authentication methods at the provider.
74+
75+
Here, a new authentication polling based variant of the OAuth2 code grant called `OAuth2CodeGrantPoll` is introduced:
76+
77+
```go
78+
type BindingProvider struct {
79+
metav1.TypeMeta `json:",inline"`
80+
81+
AuthenticationMethods []AuthenticationMethod `json:"authenticationMethods,omitempty"`
82+
}
83+
84+
type AuthenticationMethod struct {
85+
// method is the name of the authentication method. The follow methods are supported:
86+
//
87+
// - "OAuth2CodeGrant"
88+
// - "OAuth2CodeGrantPoll"
89+
//
90+
Method string `json:"method,omitempty"`
91+
92+
// OAuth2CodeGrant is the configuration for the OAuth2 code grant flow.
93+
OAuth2CodeGrant *OAuth2CodeGrant `json:"oauth2CodeGrant,omitempty"`
94+
95+
// OAuth2CodeGrant is the configuration for the OAuth2 code grant flow
96+
// using a poll based approach.
97+
OAuth2CodeGrantPoll *OAuth2CodeGrantPoll `json:"oauth2CodeGrantPoll,omitempty"`
98+
}
99+
100+
type OAuth2CodeGrantPoll struct {
101+
// sessionURL is the service provider url that the service consumer will use to create a new session.
102+
// The session is valid during the authentication and resource selection process.
103+
// Once resource selection and binding is finalized, the session is invalidated.
104+
//
105+
// +required
106+
// +kubebuilder:validation:Required
107+
// +kubebuilder:validation:MinLength=1
108+
SessionURL string `json:"sessionURL"`
109+
110+
// authenticatedURL is the service provider url that the service consumer will use to authenticate against
111+
// the service provider in case of using OIDC mode made, e.g: www.mangodb.com/kubernetes/authorize.
112+
//
113+
// +required
114+
// +kubebuilder:validation:Required
115+
// +kubebuilder:validation:MinLength=1
116+
AuthenticatedURL string `json:"authenticatedURL"`
117+
118+
// pollURL is the service provider url that is used to be poll regularly, i.e. "www.mangodb.com/bound".
119+
// The backend returns a HTTP 403 while the process is ongoing
120+
// and a HTTP 200 status code once the authentication and API resource selection is finalized.
121+
// The http response body includes the `kubebindv1alpha1.BindingResponse` object.
122+
//
123+
// +required
124+
// +kubebuilder:validation:Required
125+
// +kubebuilder:validation:MinLength=1
126+
PollURL string `json:"pollURL"`
127+
128+
// pollInterval is the expected polling interval in Go's `time.Duration` format.
129+
// If exceeded, the kube-bind backend may return a 429 Too Many Requests http status code.
130+
//
131+
// +required
132+
// +kubebuilder:validation:Required
133+
// +kubebuilder:validation:MinLength=1
134+
PollInterval string `json:"pollInterval"`
135+
}
136+
```
137+
138+
2. The kubectl `bind` renders an authentication URL on the terminal,
139+
augmented with additional session data.
140+
141+
3. The user executes the rendered URL link
142+
and finalizes authentication and API selection in his local browser.
143+
144+
4. kubectl `bind` regularly polls at every `pollInterval`.
145+
While the user process is ongoing in the user browser session
146+
the kube-bind backend returns an HTTP 403 status code.
147+
Once the user process is finalized the kube-bind backend returns an HTTP 200 status code.
148+
The response body includes the `kubebindv1alpha1.BindingResponse` object.
149+
150+
kubectl `bind` plugin blocks until authentication and API selection is finalized.
151+
152+
The following figure illustrates the poll based approach:
153+
154+
![](poll-based.png)
155+
Link: https://whimsical.com/kube-bind-auth-flow-FYCNPvj5m27pKUDVYxVRGy
156+
157+
### Backend conventions
158+
159+
#### Existing `oauth2CodeGrant` protocol
160+
161+
The existing `oauth2CodeGrant` authentication method implies the following protocol conventions:
162+
163+
- **MUST** client invokes an authentication URL given by the `authenticatedURL`
164+
- **MUST** The authentication URL includes mutually exclusively either 1. a localhost callback port parameter `p`
165+
or 2. an explicit callback URL parameter `u`.
166+
In the case of a given localhost port parameter former case a `http://localhost:<p>/callback` callback URL is assumed.
167+
- **MUST** The authentication URL includes a session ID `s` that is generated on client side.
168+
- **MUST** The authentication URL includes a cluster ID `sc that is generated on client side.
169+
170+
#### Proposed `oauth2CodeGrantPoll` protocol
171+
172+
The proposed `oauth2CodeGrantPoll` introduces the following changes:
173+
174+
1. The callback URL is removed, it is unneeded.
175+
2. Both, the session ID and cluster ID generation are now in the responsibility of the backend, not the client.
176+
3. An additional ephemeral session secret is generated on the backend side.
177+
178+
- **MUST** client invokes a HTTP POST request against the `sessionURL`.
179+
The backend returns a `kubebindv1alpha1.Oauth2CodeGrantPollSession` response with the following attributes:
180+
```go
181+
// Oauth2CodeGrantPollSession is a non-CRUD resource that is returned by the server before
182+
// authentication.
183+
// It specifies the necessary session attributes and secrets
184+
// for a polling based OAuth2 Code Grant backed binding process.
185+
type Oauth2CodeGrantPollSession struct {
186+
metav1.TypeMeta `json:",inline"`
187+
188+
// sessionID is a unique identifier for this binding session. It is valid until authentication,
189+
// resource selection, and binding is finalized.
190+
//
191+
// +required
192+
// +kubebuilder:validation:Required
193+
// +kubebuilder:validation:MinLength=1
194+
SessionID string `json:"sessionID"`
195+
196+
// clusterID is a unique identifier for the cluster where resources are bound to.
197+
// The cluster ID is valid beyond the authentication, resource selection, and binding process.
198+
//
199+
// +required
200+
// +kubebuilder:validation:Required
201+
// +kubebuilder:validation:MinLength=1
202+
ClusterID string `json:"clusterID"`
203+
204+
// sessionSecret is an ephemeral secret that is valid for this session only.
205+
// It is used to sign all subsequent requests during the authentication, resource selection, and binding process.
206+
//
207+
// +required
208+
// +kubebuilder:validation:Required
209+
// +kubebuilder:validation:MinLength=1
210+
SessionSecret string `json:"sessionSecret"`
211+
}
212+
```
213+
- **MUST** The authentication URL includes mutually exclusively either 1. a localhost callback port parameter `p`
214+
or 2. an explicit callback URL parameter `u`.
215+
In the case of a given localhost port parameter former case a `http://localhost:<p>/callback` callback URL is assumed.
216+
- **MUST** The authentication URL includes a session ID `s` that is generated on client side.
217+
- **MUST** The authentication URL includes a cluster ID `sc that is generated on client side.
218+
219+
### Reference implementation
220+
221+
The existing reference implementation needs to be extended to be able to handle the above described polling based approach. Most notably the existing implementation needs to:
222+
223+
1. Be able to handle sessions
224+
225+
TODO(sur): finalize describing the kube-bind backend, especially how session state is maintained using group-cache and consistent hashring.
226+
TODO(sur): describe trusted client concept using HMAC
227+
228+
# Alternatives
392 KB
Loading

docs/proposals/poll-based.png

520 KB
Loading

0 commit comments

Comments
 (0)