Skip to content
This repository has been archived by the owner on Apr 5, 2024. It is now read-only.

Commit

Permalink
feat: add keycloak secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
malo-octo committed Jan 10, 2024
1 parent 04eb1f1 commit aa9402d
Show file tree
Hide file tree
Showing 7 changed files with 3,643 additions and 3,436 deletions.
15 changes: 15 additions & 0 deletions .kontinuous/patches/service-account.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
Patch manifests
*/
module.exports = (manifests) => {
for (const manifest of manifests) {
const { kind } = manifest;
if (kind === "Deployment" && manifest.metadata.name === "app") {
manifest.spec.template.spec = {
...manifest.spec.template.spec,
serviceAccountName: "vault"
};
}
}
return manifests;
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"next-auth": "^4.22.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"tss-react": "^4.8.8"
"tss-react": "^4.8.8",
"node-vault": "^0.10.2"
},
"devDependencies": {
"@babel/core": "^7.22.9",
Expand Down
148 changes: 81 additions & 67 deletions src/pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next"
import type { NextRequest } from "next/server"
import NextAuth, { Session } from "next-auth";
import { Account } from "next-auth";
import { User } from "next-auth";
import { JWT } from "next-auth/jwt";
import KeycloakProvider from "next-auth/providers/keycloak";
import VaultModule from "../../../../vault/VaultModule"

import { refreshAccessToken } from "../../../lib/auth";

Expand All @@ -14,75 +17,86 @@ interface ExtendedToken extends JWT {
user: User;
}

export default NextAuth({
debug: true,
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID ?? "",
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET ?? "",
issuer: process.env.KEYCLOAK_URL ?? "",
}),
],
export default async function auth() {

callbacks: {
//@ts-ignore
async jwt({
token,
user,
account,
}: {
token: JWT;
user: User;
account: Account;
}) {
// Initial sign in
//console.log("jwt", { token, user, account });
if (account && user) {
return {
accessToken: account.access_token,
refreshToken: account.refresh_token,
idToken: account.id_token,
accessTokenExpires: account.expires_at
? account.expires_at * 1000
: null,
user,
};
}
console.log("auth method triggered !")
const vaultModule = new VaultModule("integrated");
const keycloakClientId = await vaultModule.readSecret("kv/data/integrated/keycloak_client_id")
const keycloakClientSecret = await vaultModule.readSecret("kv/data/integrated/keycloak_client_secret")
const nextauthSecret = await vaultModule.readSecret("kv/data/integrated/nextauth_secret")

// Return previous token if the access token has not expired yet
if (
token.accessTokenExpires &&
Date.now() < Number(token.accessTokenExpires)
) {
return token as ExtendedToken;
}
console.log("Secret client id: ", keycloakClientId)

// Access token has expired, try to update it
return refreshAccessToken(token);
},
// @ts-ignore
async session({
session,
token,
}: {
session: Session;
token: ExtendedToken;
}) {
if (token) {
session.user = token.user;
//@ts-ignore
session.accessToken = token.accessToken;
//@ts-ignore
session.refreshToken = token.refreshToken;
//@ts-ignore
session.idToken = token.idToken;
//@ts-ignore
session.accessTokenExpires = token.accessTokenExpires;
//@ts-ignore
session.error = token.error;
}
return NextAuth({
debug: true,
providers: [
KeycloakProvider({
clientId: keycloakClientId ?? "",
clientSecret: keycloakClientSecret ?? "",
issuer: process.env.KEYCLOAK_URL ?? "",
}),
],
secret: nextauthSecret,
callbacks: {
//@ts-ignore
async jwt({
token,
user,
account,
}: {
token: JWT;
user: User;
account: Account;
}) {
// Initial sign in
//console.log("jwt", { token, user, account });
if (account && user) {
return {
accessToken: account.access_token,
refreshToken: account.refresh_token,
idToken: account.id_token,
accessTokenExpires: account.expires_at
? account.expires_at * 1000
: null,
user,
};
}

// Return previous token if the access token has not expired yet
if (
token.accessTokenExpires &&
Date.now() < Number(token.accessTokenExpires)
) {
return token as ExtendedToken;
}

return session;
// Access token has expired, try to update it
return refreshAccessToken(token);
},
// @ts-ignore
async session({
session,
token,
}: {
session: Session;
token: ExtendedToken;
}) {
if (token) {
session.user = token.user;
//@ts-ignore
session.accessToken = token.accessToken;
//@ts-ignore
session.refreshToken = token.refreshToken;
//@ts-ignore
session.idToken = token.idToken;
//@ts-ignore
session.accessTokenExpires = token.accessTokenExpires;
//@ts-ignore
session.error = token.error;
}

return session;
},
},
},
});
})
}
48 changes: 48 additions & 0 deletions vault/VaultModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as fs from 'fs';

const vault = require("node-vault");


class VaultModule {
private vaultClient: any;
private readonly vaultRole: string
private isKubelogged: boolean

constructor(vaultRole: string) {
this.vaultClient = vault({
apiVersion: 'v1',
endpoint: "http://vault.vault-dev.svc:8200",
});
this.vaultRole = vaultRole
this.isKubelogged = false
}

async readSecret(path: string): Promise<any> {
const JWT_TOKEN_FILE="/var/run/secrets/kubernetes.io/serviceaccount/token";
const jwt = fs.readFileSync(JWT_TOKEN_FILE);

if (!this.isKubelogged) {
try {
const result = await this.vaultClient.kubernetesLogin({
"role": this.vaultRole,
"jwt": jwt.toString()
});
this.vaultClient.token = result.auth.client_token;
} catch (error) {
console.error('Error authenticating to vault instance:', error);
throw error;
}
this.isKubelogged = true
}
try {
const res = await this.vaultClient.read(path);
let obj = Object.keys(res.data.data)
return res.data.data[obj[0]]
} catch (error) {
console.error('Error reading secret:', error);
throw error;
}
}
}

export default VaultModule;
19 changes: 19 additions & 0 deletions vault/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "vault-integrated",
"version": "1.0.0",
"description": "Vault integrated for template application",
"main": "app.js",
"scripts": {
"build": "tsc",
"start": "node index.ts"
},
"dependencies": {
"node-vault": "^0.10.2"
},
"devDependencies": {
"typescript": "5.1.6"
},
"engines": {
"node": "18.11.17"
}
}
16 changes: 16 additions & 0 deletions vault/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"outDir": ".",
"rootDir": ".",
"strict": true,
"esModuleInterop": true
},
"include": [
"*.ts"
],
"exclude": [
"node_modules"
]
}
Loading

0 comments on commit aa9402d

Please sign in to comment.