February 22, 2023 6 min read

Enhancing Authentication Support

Mark Phelps
Enhancing Flipt Authentication

Photo by Roon van der Meer on Unsplash

In the previous few posts, we went over the addition of one of our most asked-for features: User Authentication support. Just when you thought that might be the end of our authentication story, we improved it even more by adding three more authentication-related features:

  1. API token configuration via the UI
  2. Configurable bootstrap token
  3. Kubernetes Service Account authentication

In this post we'll briefly go over each feature, discussing its use case, why it's an important addition to our overall auth story, as well as how to get started.

API Token Configuration

We've had basic token authentication support for authenticating your services with Flipt since v1.15. Admittedly though, it was somewhat incomplete as you could only manage those tokens via the API.

In this latest release, we added the ability to create and delete static tokens in the UI as well. This allows anyone authenticated with Flipt to see which tokens have been issued and when they expire. It also allows users to create and delete tokens as needed without having to write code to do so.

Enabling and using static token authentication is a good first step when it comes to securing the communication between Flipt and your own services. Making the management of access tokens as user-friendly as possible was one of the major acceptance criteria for this new functionality.

This feature also necessitated a new 'Settings' section of the application which we'll populate with more controls in the future.

After creating a token via the UI, you can easily copy it to your clipboard and store it in a secure location as its value will no longer be accessible from Flipt itself.

Configurable Bootstrap Token

Another improvement that we added in this release is the ability to provide a configurable bootstrap token when first enabling token authentication. Since v1.15, if an operator enabled token authentication for the first time, we would create what we call an initial bootstrap token on their behalf, logging it to STDOUT to be captured and used.

access token created	{"server": "grpc", "client_token": "ks8gyZNdU7jmB92kAIYOp4MEXTcCJbX1TdXJM01VKCs="}

This was necessary because all requests to the Flipt API would fail as soon as you enabled and required token authentication.

This meant, however, that there wasn't a great programmatic way to run Flipt with token authentication enabled for the first time, such as in the case of Kubernetes. Flipt operators would have to either:

  1. Start Flipt with authentication enabled but not required, create a token via the API, and then restart Flipt with authentication required.
  2. Start Flipt with both authentication enabled and required and try to capture the created bootstrap token from our logs.

This also presented a similar challenge when trying to run Flipt in CI, such as we do for our own integration tests, as there was no easy way to set up authentication and then restart Flipt in a test pipeline.

In this release, we added the ability for the user to optionally specify their own known bootstrap token as well as to configure it with an expiration.

Bootstrap token created with expiration
Bootstrap token created with expiration

Here's an example of how to configure a bootstrap token with a known value and an expiration of 24 hours:

      enabled: true
        token: "s3cr3t!"
        expiration: 24h

In our opinion, this provides the best of both worlds by allowing for the initialization of an authentication token with a potential known value that can expire automatically. This gives operators the ability to enable authentication from the get-go, use a known token to create more tokens, then allow the known token to quietly expire to prevent unwanted access.

More information on how to configure this feature can be found in our documentation.

Kubernetes Service Account Authentication

In most cases, static tokens are a manageable approach for getting services talking with Flipt. For security reasons, you may set an expiry on your tokens and periodically rotate them with new ones. Given you have more than one type or replica of your application(s) communicating with Flipt, you may even choose to create multiple tokens. It may be one per application type or even as many as one per replica.

For those deploying Flipt into Kubernetes environments, we have added the new kubernetes authentication method. This method takes advantage of the service account mechanisms made available in Kubernetes.

By default Kubernetes periodically writes a service account token (encoded as a JWT) into a well-known path inside each pod's filesystem. Service account tokens can be used to communicate and identify the caller with the Kubernetes API. With Flipt v1.19 you can exchange this service account token for a Flipt client token via Flipt's API.

A small amount of client-side glue code can keep your applications authenticated without having to manually create, rotate or distribute tokens.

Here's an example using curl and jq to exchange a Kubernetes service account token for a Flipt client token:

curl -s -X POST http://flipt:8080/auth/v1/method/kubernetes/serviceaccount \
  --data "{\"service_account_token\":\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\"}" | \
  jq .
  "clientToken": "pKkaEik40Nu4lJ7O37l92MNyyD38U8UlaagSmAfJoS0=",
  "authentication": {
    "id": "f191babc-57b8-4856-89b1-f324941403d7",
    "method": "METHOD_KUBERNETES",
    "expiresAt": "2024-02-20T13:39:14Z",
    "createdAt": "2023-02-20T14:11:28.962841Z",
    "updatedAt": "2023-02-20T14:11:28.962841Z",
    "metadata": {
      "io.flipt.auth.k8s.namespace": "default",
      "io.flipt.auth.k8s.pod.name": "someservice-586bfb5b6b-fmh8g",
      "io.flipt.auth.k8s.pod.uid": "b5217947-aeac-4b35-afd3-23f50d63eae9",
      "io.flipt.auth.k8s.serviceaccount.name": "default",
      "io.flipt.auth.k8s.serviceaccount.uid": "8aeb28ad-66f0-4884-bafc-e606e5eda149"

Enabling this method means Flipt implicitly trusts other services deployed into the same cluster.

While currently leveraging this new method will require some application code on the developers' part, we're actively working on a way to provide out-of-the-box support for our official clients.

As always, our documentation has more information on how to configure these features.

Please let us know what you think of these new features and if you have any questions or feedback, feel free to reach out to us on Discord, Twitter, or Mastodon!