Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2: Authentication Proposals #3831

Open
GeorgeMac opened this issue Jan 22, 2025 · 0 comments
Open

V2: Authentication Proposals #3831

GeorgeMac opened this issue Jan 22, 2025 · 0 comments
Assignees
Labels
proposal Just putting it out there v2 For consideration for v2 of Flipt

Comments

@GeorgeMac
Copy link
Member

GeorgeMac commented Jan 22, 2025

This issue captures the high-level overview of the changes going into Flipt v2 around Authentication.
The majority of these changes to authentication are motivated by new constraints, removal of deprecated concepts and some hindsight reflecting on the journey of authn in v1.

Please feel free to comment your thoughts and feelings on this.
We're open to proposed alternatives or additional improvements you would like to see around authn.

Constraints

Some of the primary motivations in v2 are around simplification of configuration, on-going maintenance and a focus on the declarative backends. The current architecture for v1 authentication is heavily dependent on having a relational database backend for credential storage (both persistent and ephemeral credentials). In v2 we intend to start from a fresh slate, with no dependencies on relational databases (at-least initially). This greatly simplifies the complexities around supporting N flavours of SQL databases.

So the changes in the proposal are geared towards preserving as much of v1's authentication capabilities without having a relational database to back them up.

Proposal

Ideally, we intend to preserve all of our existing authentication methods as possible.
V2 intends to be a drop in replacement for V1 from an evaluation perspective.
Which means supporting some form static token, JWT and k8s based authentication flows.

However, due to the constraints, we expect how these credentials are managed (written / created) will likely change. Initially, this might be a reduction in capabilities. But we may add some capabilities back in the future.

  • OIDC and GitHub

These methods we our first "session-enabled" methods, which supported login in the UI.
We intend to keeps these methods intact and working as they do today from an Oauth flow perspective and in order to support login in the UI.

However, we will change how the ephemeral generated client_tokens (these are effectively the session key that gets persisted in a cookie) are persisted in the backend.
By default, in a single write-replica Flipt situation an in-memory store should be appropriate and go a long way. The drawbacks are obviously that you won't be able to scale out a write-tier of Flipt horizontally and support login in this way. As well, restarts of Flipt would cause users to have to log back in.
This is limited, but still simple operationally and usable for some evaluation or hobbyist usecases.

Additionally, we intend to add redis support for storage of these ephemeral credentials.
Redis here will mean that Flipt can be scaled horizontally, and ephemeral credentials will persist between restarts of Flipt itself.

Because these particular credential use-cases are so tightly coupled to session based authentication, we intend to move configuration for these (i.e. whether to use in-memory or redis and how to configure connections) into the session section of Flipt configuration.

  • Kubernetes

This method has aged a little poorly. It was derived from how Vault does a service account token exchange for a Vault specific credential. As such, leveraging it involves exchanging a service account token with Flipt for a client_token to be used in the Bearer header. This means each client creates an ephemeral token that has to be tracked and shared between your instances of Flipt. This uses the exact same mechanisms as OIDC and GitHub. Effectively, creating a static token in the backing database with a lifetime matching the service account token.

In hindsight, we could just simply have the service exchange its service account token as its bearer token.
This removes the need for further persistence. SA tokens are JWTs and can be verified in a distributed manner.
If we wanted, we could go as far as caching the validation and authentication deserialization result to avoid recompute.

In order to support this on the v1 evaluation APIs with existing Kubernetes authentication helpers, I propose that the verify service account token API in v2 simply validate the SA and return it as the client_token in the response.
This will cause clients to re-supply the SA in the Bearer slot.

This will mean v1 clients are continued to be supported without the need for Flipt persist anything further.
We will add support to the Bearer token slot for the presence of k8s SA tokens.
It is not ideal as it involves us doing a pass on the credential to check if its a valid JWT / SA token first.
However, the benefits likely outway the cost there.

The other alternative which would continue to support our no relational DB constraint, would be to leverage session storage for these client tokens in the same way as OIDC / GitHub. This is on the table if folks feel strongly about retain the old flow of exchaning an SA for a client_token Flipt authored.

  • Token

This is the biggest (somewhat-breaking) change, as we no longer have online persistent storage for generated credentials. In-memory and redis are not particular appropriate for long-lived tokens (only ephemeral ones we can afford to replace automatically e.g. via another oauth flow).

The plan here is to simply remove support for token creation from this methods API.
Instead, it will become possible statically define tokens in Flipt configuration (as with everything else, we should support defining the credential either via env vars or through the filesystem here).

This is certainly a limitation of the new world. So, we will leave space for alternative backends for this method to be implemented in the future. If it becomes integral for folks to manually create tokens, instead of e.g. leveraging JWT to avoid static management of tokens, then we can look to adding more persistent storage options.

  • JWT

This will remain untouched. It should just work (tm) as-is.

Example: WIP configuration format for v2

#authentication: {
required?: bool | *false
exclude?: {
management: bool | *false
metadata: bool | *false
evaluation: bool | *false
ofrep: bool | *false
}
session?: {
domain?: string
secure?: bool
token_lifetime: =~#duration | *"24h"
state_lifetime: =~#duration | *"10m"
csrf?: {
key: string
}
storage?: *{
type: "memory"
cleanup?: #authentication.#storage_cleanup
} | {
type: "redis"
cleanup?: #authentication.#storage_cleanup
connection: {
host?: string | *"localhost"
port?: int | *6379
require_tls?: bool | *false
db?: int | *0
username?: string
password?: string
pool_size?: int | *0
min_idle_conn?: int | *0
conn_max_idle_time?: =~#duration | int | *0
net_timeout?: =~#duration | int | *0
ca_cert_path?: string
ca_cert_bytes?: string
insecure_skip_tls?: bool | *false
}
}
#storage_cleanup: {
@jsonschema(id="storage_cleanup")
interval?: =~#duration | int | *"1h"
grace_period?: =~#duration | int | *"30m"
}
}
methods?: {
token?: {
enabled?: bool | *false
storage?: {
type: "static"
tokens: [
...{
name: string
credential: string
metadata: [string]: string
},
]
}
}
oidc?: {
enabled?: bool | *false
providers?: {
{[=~"^.*$" & !~"^()$"]: #authentication.#authentication_oidc_provider}
}
email_matches?: [...] | string
}
kubernetes?: {
enabled?: bool | *false
discovery_url: string
ca_path: string
service_account_token_path: string
}
github?: {
enabled?: bool | *false
server_url?: string
api_url?: string
client_secret?: string
client_id?: string
redirect_address?: string
scopes?: [...string]
allowed_organizations?: [...] | string
allowed_teams?: [string]: [...string]
}
jwt?: {
enabled?: bool | *false
validate_claims?: {
issuer?: string
subject?: string
audiences?: [...string]
}
jwks_url?: string
public_key_file?: string
}
}
#authentication_oidc_provider: {
@jsonschema(id="authentication_oidc_provider")
issuer_url?: string
client_id?: string
client_secret?: string
redirect_address?: string
nonce?: string
scopes?: [...string]
use_pkce?: bool
}
}

Further Notes

  • There will no longer be any need for a bootstrap token as this can be solved via defining a static token in the new configuration slots (authentication.methods.token.storage.tokens[0] = {name":"static","credential":"abcdef"}).
@GeorgeMac GeorgeMac added proposal Just putting it out there v2 For consideration for v2 of Flipt labels Jan 22, 2025
@markphelps markphelps self-assigned this Jan 27, 2025
@markphelps markphelps moved this to In Progress in Roadmap Jan 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal Just putting it out there v2 For consideration for v2 of Flipt
Projects
Status: In Progress
Development

No branches or pull requests

2 participants