Websocket auth, pass access token in gke configs

This commit is contained in:
Hristo 2024-05-10 19:32:35 -04:00
parent 4e20c4ac56
commit c56a058a74
6 changed files with 49 additions and 11 deletions

View file

@ -15,8 +15,8 @@ APP_IMAGE_TAG=$(GCP_REPO)/$(GCP_PROJECT_ID)/$(PREFIX)-app:latest
CLUSTER_NAME=$(PREFIX)-cluster CLUSTER_NAME=$(PREFIX)-cluster
.PHONY: build-deplpy .PHONY: build-deploy
build-deplpy: docker-build-all deploy build-deploy: docker-build-all deploy
.PHONY: docker-build-all .PHONY: docker-build-all
@ -34,7 +34,8 @@ show_config:
&& echo $(APP_IMAGE_TAG) \ && echo $(APP_IMAGE_TAG) \
&& echo $(SEARCH_PORT) \ && echo $(SEARCH_PORT) \
&& echo $(BACKEND_PORT) \ && echo $(BACKEND_PORT) \
&& echo $(OPENAI) && echo $(OPENAI) \
&& echo $(SUPER_SECRET_KEY)
.PHONY: docker-build-push-searxng .PHONY: docker-build-push-searxng
docker-build-push-searxng: docker-build-push-searxng:
@ -72,6 +73,7 @@ deploy:
&& export TF_VAR_search_port=$(SEARCH_PORT) \ && export TF_VAR_search_port=$(SEARCH_PORT) \
&& export TF_VAR_backend_port=$(BACKEND_PORT) \ && export TF_VAR_backend_port=$(BACKEND_PORT) \
&& export TF_VAR_open_ai=$(OPENAI) \ && export TF_VAR_open_ai=$(OPENAI) \
&& export TF_VAR_secret_key=$(SUPER_SECRET_KEY) \
&& terraform apply && terraform apply

View file

@ -136,6 +136,11 @@ resource "kubernetes_deployment" "backend" {
name = "PORT" name = "PORT"
value = var.backend_port value = var.backend_port
} }
env {
# Access key for backend
name = "SUPER_SECRET_KEY"
value = var.secret_key
}
} }
} }
} }
@ -205,6 +210,11 @@ variable "open_ai" {
type = string type = string
} }
variable "secret_key" {
description = "Access key to secure backend endpoints"
type = string
}
variable "search_port" { variable "search_port" {
description = "Port for searxng service" description = "Port for searxng service"
type = number type = number

View file

@ -6,14 +6,16 @@ export const requireAccessKey = (req, res, next) => {
const authHeader = req.headers.authorization; const authHeader = req.headers.authorization;
if (authHeader) { if (authHeader) {
const token = authHeader.split(' ')[1]; if (!checkAccessKey(authHeader)) {
if (token !== getAccessKey()) {
return res.sendStatus(403); return res.sendStatus(403);
} }
next(); next();
} else { } else {
res.sendStatus(401); res.sendStatus(401);
} }
}; };
export const checkAccessKey = (authHeader) => {
const token = authHeader.split(' ')[1];
return Boolean(authHeader && (token === getAccessKey()));
};

View file

@ -9,6 +9,8 @@ import type { Embeddings } from '@langchain/core/embeddings';
import type { IncomingMessage } from 'http'; import type { IncomingMessage } from 'http';
import logger from '../utils/logger'; import logger from '../utils/logger';
import { ChatOpenAI } from '@langchain/openai'; import { ChatOpenAI } from '@langchain/openai';
import { getAccessKey } from '../config';
import { checkAccessKey } from '../auth';
export const handleConnection = async ( export const handleConnection = async (
ws: WebSocket, ws: WebSocket,
@ -18,6 +20,20 @@ export const handleConnection = async (
const searchParams = new URL(request.url, `http://${request.headers.host}`) const searchParams = new URL(request.url, `http://${request.headers.host}`)
.searchParams; .searchParams;
if (getAccessKey()) {
const securtyProtocolHeader = request.headers['sec-websocket-protocol'];
if (!checkAccessKey(securtyProtocolHeader)) {
ws.send(
JSON.stringify({
type: 'error',
data: 'Incorrect or missing authentication token.',
key: 'FAILED_AUTHORIZATION',
}),
);
ws.close();
};
}
const [chatModelProviders, embeddingModelProviders] = await Promise.all([ const [chatModelProviders, embeddingModelProviders] = await Promise.all([
getAvailableChatModelProviders(), getAvailableChatModelProviders(),
getAvailableEmbeddingModelProviders(), getAvailableEmbeddingModelProviders(),

View file

@ -7,6 +7,7 @@ import Chat from './Chat';
import EmptyChat from './EmptyChat'; import EmptyChat from './EmptyChat';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { clientFetch } from '@/lib/utils'; import { clientFetch } from '@/lib/utils';
import { getAccessKey } from '@/lib/config';
export type Message = { export type Message = {
id: string; id: string;
@ -98,7 +99,14 @@ const useSocket = (url: string) => {
wsURL.search = searchParams.toString(); wsURL.search = searchParams.toString();
const ws = new WebSocket(wsURL.toString()); let protocols: any[] = [];
const secretToken = getAccessKey();
if (secretToken) {
protocols = ["Authorization", `${secretToken}`];
};
const ws = new WebSocket(wsURL.toString(), protocols);
ws.onopen = () => { ws.onopen = () => {
console.log('[DEBUG] open'); console.log('[DEBUG] open');

View file

@ -24,14 +24,14 @@ export const formatTimeDifference = (date1: Date, date2: Date): string => {
export const clientFetch = async (path: string, payload: any): Promise<any> => { export const clientFetch = async (path: string, payload: any): Promise<any> => {
let headers = payload.headers; let headers = payload.headers;
const url = `${getBackendURL()}${path}`; const url = `${getBackendURL()}${path}`;
const secret_token = getAccessKey(); const secretToken = getAccessKey();
if (secret_token) { if (secretToken) {
if (headers == null) { if (headers == null) {
headers = {}; headers = {};
}; };
headers['Authorization'] = `Bearer ${secret_token}`; headers['Authorization'] = `Bearer ${secretToken}`;
payload.headers = headers; payload.headers = headers;
}; };