5 min read

Setting Up Traefik Proxy on k3s with Forward Auth using Authorization Header Part 2

Setting Up Traefik Proxy on k3s with Forward Auth using Authorization Header Part 2

In Part 1, we covered the basics of setting up Traefik proxy on k3s and configuring forward authentication. Now, in part 2, we will deploy a sample application to Kubernetes and set up the callback URL on a Node.js Express app to handle the authentication response from GitHub.

Step 4: Configure Traefik

We will now configure Traefik to use our Node.js Express app as the authentication provider for our web application.

  1. Create a new Kubernetes Secret with the GitHub OAuth credentials:
kubectl create secret generic myapp-oauth \
  --from-literal=client_id=<your-github-client-id> \
  --from-literal=client_secret=<your-github-client-secret>

Replace <your-github-client-id> and <your-github-client-secret> with the actual values you obtained in step 2.

  1. Create a new Kubernetes ConfigMap with the Traefik configuration:
kubectl create configmap traefik-config \
  --from-file=traefik.toml

In this case, traefik.toml is a file containing the Traefik configuration. Here’s an example configuration:

# traefik.toml
[http.middlewares.myapp-auth.forwardauth]
  address = "http://myapp.mynamespace.svc.cluster.local:3000/auth/github"
  authResponseHeaders = ["Authorization"]

[http.middlewares.myapp-auth.headers.customRequestHeaders]
  Authorization = "Bearer ${http:middleware:myapp-auth.forwardauth}"

[http.routers.myapp]
  rule = "Host(`myapp.example.com`)"
  entryPoints = ["websecure"]
  middlewares = ["myapp-auth"]
  service = "myapp-service"

[http.services.myapp-service]
  [http.services.myapp-service.loadBalancer]
    passHostHeader = true
    servers = [
      { url = "http://myapp.mynamespace.svc.cluster.local" }
    ]

In this configuration, we have defined a middleware called myapp-auth that uses the forwardauth plugin to forward authentication requests to our Node.js Express app. The authResponseHeaders option tells Traefik to include the Authorization header in the authentication response.

We have also defined a custom request header called Authorization that includes the access token returned by our Node.js Express app. This header will be added to all requests to the myapp service.

Finally, we have defined a router called myapp that listens for requests to the myapp.example.com hostname and uses the myapp-auth middleware. The router forwards requests to a Kubernetes service called myapp-service.

Note that you should replace myapp with the actual name of your application.

Once you have created the secret and the configmap, you can deploy Traefik to your Kubernetes cluster:

kubectl apply -f traefik.yaml

Replace traefik.yaml with the actual name of your Traefik deployment file.

Step 5: Deploy the Application

We are now ready to deploy our application to Kubernetes. Here’s how:

  1. Create a new file called deployment.yaml with the following contents:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: production
        - name: PORT
          value: "3000"
        - name: CLIENT_ID
          valueFrom:
            secretKeyRef
  1. Deploy the application to Kubernetes:
kubectl apply -f deployment.yaml
  1. Create a new Kubernetes Service for the application:
kubectl expose deployment myapp --port=80 --target-port=3000 --type=ClusterIP
  1. Create a new Kubernetes Ingress for the application:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    kubernetes.io/ingress.class: traefik
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp
            port:
              name: http

In this Ingress configuration, we are using the traefik ingress class to route traffic to our application. We are also using the letsencrypt-prod cluster issuer to automatically obtain a TLS certificate from Let’s Encrypt.

Replace myapp.example.com with the actual hostname of your application.

Once you have deployed your application, you should be able to access it by visiting https://myapp.example.com in your web browser.

Step 6: Implement the Callback URL on Node.js Express

Finally, we need to implement the callback URL on our Node.js Express app to handle the authentication response from GitHub.

  1. Install the passport-github2 and jsonwebtoken packages:
npm install passport-github2 jsonwebtoken
  1. Create a new file called auth.js with the following contents:
const passport = require('passport');
const { Strategy: GitHubStrategy } = require('passport-github2');
const jwt = require('jsonwebtoken');

const clientID = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const jwtSecret = process.env.JWT_SECRET;

passport.use(new GitHubStrategy({
  clientID,
  clientSecret,
  callbackURL: '/auth/github/callback'
}, (accessToken, refreshToken, profile, done) => {
  const jwtPayload = {
    id: profile.id,
    username: profile.username
  };
  const jwtToken = jwt.sign(jwtPayload, jwtSecret, { expiresIn: '1h' });
  return done(null, { jwtToken });
}));

module.exports = passport;

In this file, we are using the passport-github2 package to handle the authentication with GitHub. We are also using the jsonwebtoken package to create a JWT token with the user’s ID and username.

Replace jwtSecret with a secret key for signing the JWT token.

  1. Create a new file called index.js with the following contents:
const express = require('express');
const session = require('express-session');
const auth = require('./auth');

const app = express();
const port = process.env.PORT || 3000;

app.use(session({
  secret: 'my-secret',
  resave: false,
  saveUninitialized: false
}));

app.use(auth.initialize());
app.use(auth.session());

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.get('/auth/github', auth.authenticate('github'));

app.get('/auth/github/callback', auth.authenticate('github', { failureRedirect: '/login' }), (req, res) => {
  res.redirect('/');
});

app.listen(port, () => {
  console.log(`App listening at http://localhost:${port}`);
});

In this file, we are using the express package to create an HTTP server. We are also using the express-session package to handle sessions.

We are initializing passport using the auth module that we created in auth.js. We are also using the session middleware to enable session support.

We have defined three routes:

  • /: This is the default route that displays a “Hello World!” message.
  • /auth/github: This route redirects the user to GitHub for authentication.
  • /auth/github/callback: This route handles the authentication response from GitHub.

When the user visits the /auth/github route, they will be redirected to the GitHub authentication page. After the user has authenticated with GitHub, they will be redirected to the /auth/github/callback route.

In the callback route, we are using the auth.authenticate middleware to handle the authentication response from GitHub. If the authentication is successful, we will redirect the user to the default route.

  1. Start the Node.js Express app:
npm start

You should now be able to visit http://localhost:3000 in your web browser and see the “Hello World!” message. When you visit http://localhost:3000/auth/github, you should be redirected to GitHub for authentication. After you have authenticated with GitHub, you should be redirected back to http://localhost:3000 and see the “Hello World!” message again.

Congratulations! You have successfully set up Traefik proxy on k3s with forward auth using the Authorization header, deployed a sample application to Kubernetes, and implemented the callback URL on a Node.js Express app to handle the authentication response from GitHub.

Conclusion

Traefik proxy is a powerful tool for managing and routing traffic in a Kubernetes cluster. By setting up forward authentication with the Authorization header, you can add an extra layer of security to your applications and ensure that only authorized users can access them.

In this tutorial, we covered the following:

  • Setting up Traefik proxy on k3s
  • Configuring forward authentication with the Authorization header
  • Deploying a sample application to Kubernetes
  • Implementing the callback URL on a Node.js Express app to handle the authentication response from GitHub

I hope this tutorial has been helpful in getting you started with Traefik proxy and forward authentication. Happy coding!