Dex is a nice little application that you can add to your Kubernetes cluster (easier when combined with Jenkins-X and Helm) that allows your user to authenticate via various OAuth providers. We are only interested in using Github as OAuth provider so this post will be focused on Github.
Helm Chart
We use this chart for our installation which is an official chart for Dex.
https://artifacthub.io/packages/helm/dex/dex
Our initial setup is very simple and here is an example chart values.
config:
issuer: https://example.com/dex
storage:
type: kubernetes
config:
inCluster: true
staticClients:
- id: web-app
name: Web App
redirectURIs:
- https://example.com/auth/callback
secret: $DEX_CLIENT_SECRET
connectors:
- type: github
id: github
name: Github
config:
clientID: <client-id-here>
clientSecret: $GITHUB_CLIENT_SECRET
redirectURI: https://example.com/dex/callback
scopes:
- openid
- email
- profile
- groups
- federated:id
enablePasswordDB: false
oauth2:
skipApprovalScreen: true
alwaysShowLoginScreen: false
envFrom:
- secretRef:
name: dex-secrets
And our initial secret provides the following keys mapped to environment variables:
- GITHUB_CLIENT_SECRET
- DEX_CLIENT_SECRET
Dex Configuration
Based on our initial test, the secrets are populated properly into the environment variable. However, when we tried to use the secrets, turns out, the $DEX_CLIENT_SECRET
value was passed as string literal. We don’t know whether this is the same with $GITHUB_CLIENT_SECRET
. We cannot store the secret as plain text as it is unacceptable.
Based on Dex helm chart documentation, we can pass a secret by the key configSecret.name
which should contain a key called config.yaml
and that the value should be the dex config you wanted to pass. This means we will pass the whole content of a YAML file into this secret which includes new lines. Jenkins-X jx secret edit
doesn’t like new lines but we have a solution for that.
Populate the whole config into secret
First, we need to change the dex helm chart values into something like this:
configSecret:
name: dex-secrets
Then add a new key in our existing secret called config.yaml
apiVersion: v1
data:
GITHUB_CLIENT_SECRET: ""
DEX_CLIENT_SECRET: ""
config.yaml: ""
kind: Secret
metadata:
name: dex-secrets
type: Opaque
We don’t bother removing the old keys as we are also referencing them from our other applications.
Here is our full config file (secrets redacted of course).
issuer: https://example.com/dex
storage:
type: kubernetes
config:
inCluster: true
staticClients:
- id: web-app
name: Web App
redirectURIs:
- https://example.com/auth/callback
secret: <web-app-client-secret-here>
connectors:
- type: github
id: github
name: Github
config:
clientID: <client-id-here>
clientSecret: <client-secret-here>
redirectURI: https://example.com/dex/callback
scopes:
- openid
- email
- profile
- groups
- federated:id
enablePasswordDB: false
oauth2:
skipApprovalScreen: true
alwaysShowLoginScreen: false
We can’t just copy and paste it into jx secret edit
as new lines will break it. We need to convert this whole config into a single line using a very simple nodejs script. What it does is convert new lines into string literal \n
and dumps the text into output.
// File: multi-line-to-single-line.js
const data = `this
is
multi
line`;
const lines = data.split("\n");
const line = lines.join('\\n');
console.log(line);
Paste in the full config into data
constant then run this in your terminal (assuming a Linux-like environment).
node multi-line-to-single-line.js > single-line-config.txt
With this, we can get the single line config. Using jx secret edit
, run the following:
jx secret edit -f secret-name
Then paste the single line text into the config.yaml
key. Wait for Jenkins-X/Kubernetes propagate the changes into your pod for it to take effect.
That’s it!
You have just avoided storing your secret in your codebase!
Featured image by Pixabay.