-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add protected prometheus metrics endpoint at website
- Loading branch information
Nikita Pavlovskiy
committed
Aug 15, 2023
1 parent
969c7c5
commit 78b5c07
Showing
11 changed files
with
845 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { NextApiRequest, NextApiResponse } from "next"; | ||
import { register } from "prom-client"; | ||
import { verifyToken } from "../../../utils/monitoring/metricsCollectorTokenVerifier"; | ||
|
||
export default async (req: NextApiRequest, res: NextApiResponse) => { | ||
const accessTokenBearer = req.headers["authorization"]; | ||
|
||
if (!accessTokenBearer) { | ||
res.status(401); | ||
return res.end(); | ||
} | ||
|
||
const accessToken = accessTokenBearer.slice("Bearer ".length); | ||
|
||
if (!(await verifyToken(accessToken, "metrics-scraper"))) { | ||
res.status(401); | ||
return res.end(); | ||
} | ||
|
||
res.setHeader("Content-type", register.contentType); | ||
res.send(await register.metrics()); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
apps/website/utils/monitoring/metricsCollectorTokenVerifier.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { JwtHeader, JwtPayload, decode, verify } from "jsonwebtoken"; | ||
import { JwksClient, SigningKey } from "jwks-rsa"; | ||
|
||
const getKey = async (header: JwtHeader): Promise<SigningKey> => { | ||
const client = new JwksClient({ | ||
jwksUri: `${process.env.KEYCLOAK_REALM_ADDRESS}/protocol/openid-connect/certs`, | ||
}); | ||
|
||
return await client.getSigningKey(header.kid); | ||
}; | ||
|
||
export const verifyToken = async (token: string, requiredRole: string): Promise<boolean> => { | ||
try { | ||
const jwtDecoded = decode(token, { complete: true }); | ||
const signingKey = await getKey(jwtDecoded?.header as JwtHeader); | ||
const aaa = verify(token, signingKey.getPublicKey(), { complete: true }); | ||
const roles = (aaa.payload as JwtPayload & { roles: string[] })["roles"]; | ||
if (!roles.includes(requiredRole)) { | ||
throw new Error(`Role <${requiredRole}> is missing from the roles list`); | ||
} | ||
return true; | ||
} catch (err) { | ||
console.error({ err }); | ||
return false; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { NextRequest, NextResponse } from "next/server"; | ||
import { Counter, register, collectDefaultMetrics } from "prom-client"; | ||
|
||
const globalCounters = globalThis as unknown as { | ||
defaultMetricsCollected: true | undefined; | ||
httpVisits: Counter | undefined; | ||
}; | ||
|
||
let httpVisits: Counter; | ||
|
||
if (process.env.NODE_ENV === "production") { | ||
collectDefaultMetrics(); | ||
httpVisits = new Counter({ | ||
name: "http_requests_total", | ||
help: "Total number of HTTP requests", | ||
labelNames: ["path", "userAgent"], | ||
}); | ||
} else { | ||
if (!globalCounters.defaultMetricsCollected) { | ||
collectDefaultMetrics(); | ||
globalCounters.defaultMetricsCollected = true; | ||
} | ||
if (!globalCounters.httpVisits) { | ||
globalCounters.httpVisits = new Counter({ | ||
name: "http_requests_total", | ||
help: "Total number of HTTP requests", | ||
labelNames: ["path", "userAgent"], | ||
}); | ||
} | ||
httpVisits = globalCounters.httpVisits; | ||
} | ||
|
||
export const addHttpVisit = (path: string, userAgent: string) => | ||
httpVisits.inc({ | ||
path, | ||
userAgent, | ||
}); |