mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Update audit log service actor v3 filter, status toggle permissions, add JWT service token secret, for ST V3
This commit is contained in:
@@ -26,6 +26,7 @@ export const getJwtSignupLifetime = async () => (await client.getSecret("JWT_SIG
|
||||
export const getJwtProviderAuthSecret = async () => (await client.getSecret("JWT_PROVIDER_AUTH_SECRET")).secretValue;
|
||||
export const getJwtProviderAuthLifetime = async () => (await client.getSecret("JWT_PROVIDER_AUTH_LIFETIME")).secretValue || "15m";
|
||||
export const getJwtSignupSecret = async () => (await client.getSecret("JWT_SIGNUP_SECRET")).secretValue;
|
||||
export const getJwtServiceTokenSecret = async () => (await client.getSecret("JWT_SERVICE_TOKEN_SECRET")).secretValue;
|
||||
export const getMongoURL = async () => (await client.getSecret("MONGO_URL")).secretValue;
|
||||
export const getNodeEnv = async () => (await client.getSecret("NODE_ENV")).secretValue || "production";
|
||||
export const getVerboseErrorOutput = async () => (await client.getSecret("VERBOSE_ERROR_OUTPUT")).secretValue === "true" && true;
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import { BadRequestError, ResourceNotFoundError } from "../../utils/errors";
|
||||
import { EEAuditLogService } from "../../ee/services";
|
||||
import { getJwtServiceTokenSecret } from "../../config";
|
||||
|
||||
/**
|
||||
* Create service token data
|
||||
@@ -82,7 +83,7 @@ export const createServiceTokenData = async (req: Request, res: Response) => {
|
||||
_id: serviceTokenData._id.toString()
|
||||
},
|
||||
expiresIn,
|
||||
secret: "hello" // TODO: replace with real secret
|
||||
secret: await getJwtServiceTokenSecret()
|
||||
});
|
||||
|
||||
await EEAuditLogService.createAuditLog(
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
Membership,
|
||||
Secret,
|
||||
ServiceTokenData,
|
||||
ServiceTokenDataV3,
|
||||
TFolderSchema,
|
||||
User,
|
||||
Workspace
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
SecretSnapshot,
|
||||
SecretVersion,
|
||||
ServiceActor,
|
||||
ServiceActorV3,
|
||||
TFolderRootVersionSchema,
|
||||
TrustedIP,
|
||||
UserActor
|
||||
@@ -653,7 +655,7 @@ export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSub.AuditLogs
|
||||
);
|
||||
|
||||
|
||||
const query = {
|
||||
workspace: new Types.ObjectId(workspaceId),
|
||||
...(eventType
|
||||
@@ -668,13 +670,13 @@ export const getWorkspaceAuditLogs = async (req: Request, res: Response) => {
|
||||
: {}),
|
||||
...(actor
|
||||
? {
|
||||
"actor.type": actor.split("-", 2)[0],
|
||||
"actor.type": actor.substring(0, actor.lastIndexOf("-")),
|
||||
...(actor.split("-", 2)[0] === ActorType.USER
|
||||
? {
|
||||
"actor.metadata.userId": actor.split("-", 2)[1]
|
||||
"actor.metadata.userId": actor.substring(actor.lastIndexOf("-") + 1)
|
||||
}
|
||||
: {
|
||||
"actor.metadata.serviceId": actor.split("-", 2)[1]
|
||||
"actor.metadata.serviceId": actor.substring(actor.lastIndexOf("-") + 1)
|
||||
})
|
||||
}
|
||||
: {}),
|
||||
@@ -742,9 +744,27 @@ export const getWorkspaceAuditLogActorFilterOpts = async (req: Request, res: Res
|
||||
name: serviceTokenData.name
|
||||
}
|
||||
}));
|
||||
|
||||
const serviceV3Actors: ServiceActorV3[] = (
|
||||
await ServiceTokenDataV3.find({
|
||||
workspace: new Types.ObjectId(workspaceId)
|
||||
})
|
||||
).map((serviceTokenData) => ({
|
||||
type: ActorType.SERVICE_V3,
|
||||
metadata: {
|
||||
serviceId: serviceTokenData._id.toString(),
|
||||
name: serviceTokenData.name
|
||||
}
|
||||
}));
|
||||
|
||||
const actors = [
|
||||
...userActors,
|
||||
...serviceActors,
|
||||
...serviceV3Actors
|
||||
];
|
||||
|
||||
return res.status(200).send({
|
||||
actors: [...userActors, ...serviceActors]
|
||||
actors
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
getJwtProviderAuthSecret,
|
||||
getJwtRefreshLifetime,
|
||||
getJwtRefreshSecret,
|
||||
getJwtServiceTokenSecret
|
||||
} from "../config";
|
||||
import {
|
||||
AuthMode
|
||||
@@ -87,7 +88,7 @@ export const validateAuthMode = ({
|
||||
break;
|
||||
case "proj_token":
|
||||
authMode = AuthMode.SERVICE_TOKEN_V3;
|
||||
authTokenValue = parts.slice(1).join('.');
|
||||
authTokenValue = parts.slice(1).join(".");
|
||||
break;
|
||||
default:
|
||||
authMode = AuthMode.JWT;
|
||||
@@ -239,21 +240,28 @@ export const getAuthSTDPayload = async ({
|
||||
authTokenValue: string;
|
||||
}): Promise<ServiceTokenV3AuthData> => {
|
||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||
jwt.verify(authTokenValue, "hello") // TODO: replace with real secret
|
||||
jwt.verify(authTokenValue, await getJwtServiceTokenSecret())
|
||||
);
|
||||
|
||||
const serviceTokenData = await ServiceTokenDataV3.findOneAndUpdate(
|
||||
{
|
||||
_id: new Types.ObjectId(decodedToken._id),
|
||||
isActive: true
|
||||
},
|
||||
{
|
||||
lastUsed: new Date()
|
||||
},
|
||||
{
|
||||
new: true
|
||||
}
|
||||
);
|
||||
|
||||
const serviceTokenData = await ServiceTokenDataV3.findOne({
|
||||
_id: new Types.ObjectId(decodedToken._id),
|
||||
isActive: true
|
||||
});
|
||||
|
||||
if (!serviceTokenData) {
|
||||
throw UnauthorizedRequestError({
|
||||
message: "Failed to authenticate" // standardize auth error messages
|
||||
message: "Failed to authenticate"
|
||||
});
|
||||
} else if (serviceTokenData?.expiresAt && new Date(serviceTokenData.expiresAt) < new Date()) {
|
||||
// case: service token expired
|
||||
// TODO: test expired token
|
||||
await ServiceTokenDataV3.findByIdAndUpdate(
|
||||
serviceTokenData._id,
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export enum ActorType {
|
||||
USER = "user",
|
||||
SERVICE = "service"
|
||||
SERVICE = "service",
|
||||
SERVICE_V3 = "service-v3"
|
||||
}
|
||||
|
||||
export enum UserAgentType {
|
||||
|
||||
@@ -35,9 +35,15 @@ export interface ServiceActor {
|
||||
metadata: ServiceActorMetadata;
|
||||
}
|
||||
|
||||
export interface ServiceActorV3 {
|
||||
type: ActorType.SERVICE_V3;
|
||||
metadata: ServiceActorMetadata;
|
||||
}
|
||||
|
||||
export type Actor =
|
||||
| UserActor
|
||||
| ServiceActor;
|
||||
| ServiceActor
|
||||
| ServiceActorV3;
|
||||
|
||||
interface GetSecretsEvent {
|
||||
type: EventType.GET_SECRETS;
|
||||
|
||||
@@ -50,6 +50,12 @@ export const LogsFilter = ({
|
||||
{actor.metadata.name}
|
||||
</SelectItem>
|
||||
);
|
||||
case ActorType.SERVICE_V3:
|
||||
return (
|
||||
<SelectItem value={`${actor.type}-${actor.metadata.serviceId}`} key={`service-actor-v3-filter-${actor.metadata.serviceId}`}>
|
||||
{actor.metadata.name}
|
||||
</SelectItem>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<SelectItem value="actor-none" key="actor-none">
|
||||
|
||||
@@ -29,6 +29,13 @@ export const LogsTableRow = ({
|
||||
<p>Service token</p>
|
||||
</Td>
|
||||
);
|
||||
case ActorType.SERVICE_V3:
|
||||
return (
|
||||
<Td>
|
||||
<p>{`${actor.metadata.name}`}</p>
|
||||
<p>Service token V3</p>
|
||||
</Td>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<Td />
|
||||
|
||||
@@ -50,7 +50,7 @@ export const ServiceTokenV3Section = withProjectPermission(
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="flex justify-between mb-8">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">
|
||||
(New) Service Tokens
|
||||
Service Tokens V3 (Beta)
|
||||
</p>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
|
||||
@@ -114,16 +114,24 @@ export const ServiceTokenV3Table = ({
|
||||
<Tr className="h-10" key={`st-v3-${_id}`}>
|
||||
<Td>{name}</Td>
|
||||
<Td>
|
||||
<Switch
|
||||
id={`enable-service-token-${_id}`}
|
||||
onCheckedChange={(value) => handleToggleServiceTokenDataStatus({
|
||||
serviceTokenDataId: _id,
|
||||
isActive: value
|
||||
})}
|
||||
isChecked={isActive}
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Edit}
|
||||
a={ProjectPermissionSub.ServiceTokens}
|
||||
>
|
||||
<p className="w-12 mr-4">{isActive ? "Active" : "Inactive"}</p>
|
||||
</Switch>
|
||||
{(isAllowed) => (
|
||||
<Switch
|
||||
id={`enable-service-token-${_id}`}
|
||||
onCheckedChange={(value) => handleToggleServiceTokenDataStatus({
|
||||
serviceTokenDataId: _id,
|
||||
isActive: value
|
||||
})}
|
||||
isChecked={isActive}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
<p className="w-12 mr-4">{isActive ? "Active" : "Inactive"}</p>
|
||||
</Switch>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</Td>
|
||||
<Td>
|
||||
{scopes.map((scope) => {
|
||||
|
||||
Reference in New Issue
Block a user