>>FIRST MISSION//LOGS//authorization header//setting-up-traefik-proxy-on-k3s-with-forward-auth-using-authorization-header-part-2.MD
[ + ] TARGET_LOCKED200 OK
MAR 31, 2023timer 3 MIN READSYS_TAG: authorization header STATUS: VERIFIED_WORKING

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

ENGINE: KERNEL // STABLE
BASE_ARCH: x86_64
HOST: VASTORIGINS.COM
GPG: OKSIG_ID: 0x4EB27DB0
Setting Up Traefik Proxy on k3s with Forward Auth using Authorization Header Part 2
SPEC_IMAGE // PROVENANCE_VERIFIED

In Part 1, we covered the basics of setting up Traefik proxy on k3s and configuring forward authentication. We installed Traefik, created the GitHub OAuth app, and scaffolded the Node.js Express app with its callback route stubbed out. Now, in part 2, we will deploy a sample application to Kubernetes, wire the callback URL in the Express app so it really handles the authentication response from GitHub, and connect everything through the ingress.

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. Keeping credentials in a Secret instead of hardcoding them in YAML is what lets you deploy the same manifests anywhere safely.

  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, so the downstream app can read it.

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

Note that the CLIENT_ID environment variable is wired to pull from the Kubernetes Secret we created, using a secretKeyRef. Fill in the secret name and key to match your setup, since this is where the app gets its OAuth credentials in production.

  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, so the whole thing is HTTPS out of the box.

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. This is where the TODO comments from part 1 get replaced with real code.

  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, which becomes the payload that Traefik forwards in the Authorization header.

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.

🧠 Final Thoughts

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, without making every microservice implement login on its own.

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. The pattern scales well: swap GitHub for any OAuth provider, and swap the demo app for your real service, and you have a production grade auth wall in front of your whole cluster. Happy coding!

[ SIGNATURE VERIFIED // GPG 0x4EB27DB0 // PROVENANCE SECURE ]
➔ RETURN TO LOGS