mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-27 09:38:50 +00:00
Resolve merge conflicts
This commit is contained in:
@ -74,21 +74,21 @@ jobs:
|
||||
uses: pr-mpt/actions-commit-hash@v2
|
||||
- name: Download task definition
|
||||
run: |
|
||||
aws ecs describe-task-definition --task-definition infisical-prod-platform --query taskDefinition > task-definition.json
|
||||
aws ecs describe-task-definition --task-definition infisical-core-platform --query taskDefinition > task-definition.json
|
||||
- name: Render Amazon ECS task definition
|
||||
id: render-web-container
|
||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||
with:
|
||||
task-definition: task-definition.json
|
||||
container-name: infisical-prod-platform
|
||||
container-name: infisical-core-platform
|
||||
image: infisical/staging_infisical:${{ steps.commit.outputs.short }}
|
||||
environment-variables: "LOG_LEVEL=info"
|
||||
- name: Deploy to Amazon ECS service
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.render-web-container.outputs.task-definition }}
|
||||
service: infisical-prod-platform
|
||||
cluster: infisical-prod-platform
|
||||
service: infisical-core-platform
|
||||
cluster: infisical-core-platform
|
||||
wait-for-service-stability: true
|
||||
|
||||
production-postgres-deployment:
|
||||
@ -135,6 +135,6 @@ jobs:
|
||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||
with:
|
||||
task-definition: ${{ steps.render-web-container.outputs.task-definition }}
|
||||
service: infisical-prod-platform
|
||||
cluster: infisical-prod-platform
|
||||
service: infisical-core-platform
|
||||
cluster: infisical-core-platform
|
||||
wait-for-service-stability: true
|
||||
|
4
backend/src/@types/fastify.d.ts
vendored
4
backend/src/@types/fastify.d.ts
vendored
@ -32,7 +32,7 @@ import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-se
|
||||
import { TGroupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
||||
import { TIdentityServiceFactory } from "@app/services/identity/identity-service";
|
||||
import { TIdentityAccessTokenServiceFactory } from "@app/services/identity-access-token/identity-access-token-service";
|
||||
import { TIdentityAwsIamAuthServiceFactory } from "@app/services/identity-aws-iam-auth/identity-aws-iam-auth-service";
|
||||
import { TIdentityAwsAuthServiceFactory } from "@app/services/identity-aws-auth/identity-aws-auth-service";
|
||||
import { TIdentityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service";
|
||||
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
||||
import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
|
||||
@ -118,7 +118,7 @@ declare module "fastify" {
|
||||
identityProject: TIdentityProjectServiceFactory;
|
||||
identityUa: TIdentityUaServiceFactory;
|
||||
identityGcpAuth: TIdentityGcpAuthServiceFactory;
|
||||
identityAwsIamAuth: TIdentityAwsIamAuthServiceFactory;
|
||||
identityAwsAuth: TIdentityAwsAuthServiceFactory;
|
||||
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
|
||||
accessApprovalRequest: TAccessApprovalRequestServiceFactory;
|
||||
secretApprovalPolicy: TSecretApprovalPolicyServiceFactory;
|
||||
|
14
backend/src/@types/knex.d.ts
vendored
14
backend/src/@types/knex.d.ts
vendored
@ -59,9 +59,9 @@ import {
|
||||
TIdentityAccessTokens,
|
||||
TIdentityAccessTokensInsert,
|
||||
TIdentityAccessTokensUpdate,
|
||||
TIdentityAwsIamAuths,
|
||||
TIdentityAwsIamAuthsInsert,
|
||||
TIdentityAwsIamAuthsUpdate,
|
||||
TIdentityAwsAuths,
|
||||
TIdentityAwsAuthsInsert,
|
||||
TIdentityAwsAuthsUpdate,
|
||||
TIdentityGcpAuths,
|
||||
TIdentityGcpAuthsInsert,
|
||||
TIdentityGcpAuthsUpdate,
|
||||
@ -337,10 +337,10 @@ declare module "knex/types/tables" {
|
||||
TIdentityGcpAuthsInsert,
|
||||
TIdentityGcpAuthsUpdate
|
||||
>;
|
||||
[TableName.IdentityAwsIamAuth]: Knex.CompositeTableType<
|
||||
TIdentityAwsIamAuths,
|
||||
TIdentityAwsIamAuthsInsert,
|
||||
TIdentityAwsIamAuthsUpdate
|
||||
[TableName.IdentityAwsAuth]: Knex.CompositeTableType<
|
||||
TIdentityAwsAuths,
|
||||
TIdentityAwsAuthsInsert,
|
||||
TIdentityAwsAuthsUpdate
|
||||
>;
|
||||
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
||||
TIdentityUaClientSecrets,
|
||||
|
@ -4,8 +4,8 @@ import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityAwsIamAuth))) {
|
||||
await knex.schema.createTable(TableName.IdentityAwsIamAuth, (t) => {
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityAwsAuth))) {
|
||||
await knex.schema.createTable(TableName.IdentityAwsAuth, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
|
||||
t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable();
|
||||
@ -14,16 +14,17 @@ export async function up(knex: Knex): Promise<void> {
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("identityId").notNullable().unique();
|
||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||
t.string("type").notNullable();
|
||||
t.string("stsEndpoint").notNullable();
|
||||
t.string("allowedPrincipalArns").notNullable();
|
||||
t.string("allowedAccountIds").notNullable();
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityAwsIamAuth);
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityAwsAuth);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityAwsIamAuth);
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityAwsIamAuth);
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityAwsAuth);
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityAwsAuth);
|
||||
}
|
@ -7,7 +7,7 @@ import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const IdentityAwsIamAuthsSchema = z.object({
|
||||
export const IdentityAwsAuthsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
accessTokenTTL: z.coerce.number().default(7200),
|
||||
accessTokenMaxTTL: z.coerce.number().default(7200),
|
||||
@ -16,11 +16,12 @@ export const IdentityAwsIamAuthsSchema = z.object({
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
identityId: z.string().uuid(),
|
||||
type: z.string(),
|
||||
stsEndpoint: z.string(),
|
||||
allowedPrincipalArns: z.string(),
|
||||
allowedAccountIds: z.string()
|
||||
});
|
||||
|
||||
export type TIdentityAwsIamAuths = z.infer<typeof IdentityAwsIamAuthsSchema>;
|
||||
export type TIdentityAwsIamAuthsInsert = Omit<z.input<typeof IdentityAwsIamAuthsSchema>, TImmutableDBKeys>;
|
||||
export type TIdentityAwsIamAuthsUpdate = Partial<Omit<z.input<typeof IdentityAwsIamAuthsSchema>, TImmutableDBKeys>>;
|
||||
export type TIdentityAwsAuths = z.infer<typeof IdentityAwsAuthsSchema>;
|
||||
export type TIdentityAwsAuthsInsert = Omit<z.input<typeof IdentityAwsAuthsSchema>, TImmutableDBKeys>;
|
||||
export type TIdentityAwsAuthsUpdate = Partial<Omit<z.input<typeof IdentityAwsAuthsSchema>, TImmutableDBKeys>>;
|
@ -17,7 +17,7 @@ export * from "./group-project-memberships";
|
||||
export * from "./groups";
|
||||
export * from "./identities";
|
||||
export * from "./identity-access-tokens";
|
||||
export * from "./identity-aws-iam-auths";
|
||||
export * from "./identity-aws-auths";
|
||||
export * from "./identity-gcp-auths";
|
||||
export * from "./identity-org-memberships";
|
||||
export * from "./identity-project-additional-privilege";
|
||||
|
@ -46,7 +46,7 @@ export enum TableName {
|
||||
IdentityUniversalAuth = "identity_universal_auths",
|
||||
IdentityGcpAuth = "identity_gcp_auths",
|
||||
IdentityUaClientSecret = "identity_ua_client_secrets",
|
||||
IdentityAwsIamAuth = "identity_aws_iam_auths",
|
||||
IdentityAwsAuth = "identity_aws_auths",
|
||||
IdentityOrgMembership = "identity_org_memberships",
|
||||
IdentityProjectMembership = "identity_project_memberships",
|
||||
IdentityProjectMembershipRole = "identity_project_membership_role",
|
||||
@ -146,5 +146,5 @@ export enum ProjectUpgradeStatus {
|
||||
export enum IdentityAuthMethod {
|
||||
Univeral = "universal-auth",
|
||||
GCP_AUTH = "gcp-auth",
|
||||
AWS_IAM_AUTH = "aws-iam-auth"
|
||||
AWS_AUTH = "aws-auth"
|
||||
}
|
||||
|
@ -70,10 +70,10 @@ export enum EventType {
|
||||
ADD_IDENTITY_GCP_AUTH = "add-identity-gcp -auth",
|
||||
UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth",
|
||||
GET_IDENTITY_GCP_AUTH = "get-identity-gcp-auth",
|
||||
LOGIN_IDENTITY_AWS_IAM_AUTH = "login-identity-aws-iam-auth",
|
||||
ADD_IDENTITY_AWS_IAM_AUTH = "add-identity-aws-iam-auth",
|
||||
UPDATE_IDENTITY_AWS_IAM_AUTH = "update-identity-aws-iam-auth",
|
||||
GET_IDENTITY_AWS_IAM_AUTH = "get-identity-aws-iam-auth",
|
||||
LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth",
|
||||
ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth",
|
||||
UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth",
|
||||
GET_IDENTITY_AWS_AUTH = "get-identity-aws-auth",
|
||||
CREATE_ENVIRONMENT = "create-environment",
|
||||
UPDATE_ENVIRONMENT = "update-environment",
|
||||
DELETE_ENVIRONMENT = "delete-environment",
|
||||
@ -460,17 +460,17 @@ interface GetIdentityGcpAuthEvent {
|
||||
};
|
||||
}
|
||||
|
||||
interface LoginIdentityAwsIamAuthEvent {
|
||||
type: EventType.LOGIN_IDENTITY_AWS_IAM_AUTH;
|
||||
interface LoginIdentityAwsAuthEvent {
|
||||
type: EventType.LOGIN_IDENTITY_AWS_AUTH;
|
||||
metadata: {
|
||||
identityId: string;
|
||||
identityAwsIamAuthId: string;
|
||||
identityAwsAuthId: string;
|
||||
identityAccessTokenId: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface AddIdentityAwsIamAuthEvent {
|
||||
type: EventType.ADD_IDENTITY_AWS_IAM_AUTH;
|
||||
interface AddIdentityAwsAuthEvent {
|
||||
type: EventType.ADD_IDENTITY_AWS_AUTH;
|
||||
metadata: {
|
||||
identityId: string;
|
||||
stsEndpoint: string;
|
||||
@ -483,8 +483,8 @@ interface AddIdentityAwsIamAuthEvent {
|
||||
};
|
||||
}
|
||||
|
||||
interface UpdateIdentityAwsIamAuthEvent {
|
||||
type: EventType.UPDATE_IDENTITY_AWS_IAM_AUTH;
|
||||
interface UpdateIdentityAwsAuthEvent {
|
||||
type: EventType.UPDATE_IDENTITY_AWS_AUTH;
|
||||
metadata: {
|
||||
identityId: string;
|
||||
stsEndpoint?: string;
|
||||
@ -497,8 +497,8 @@ interface UpdateIdentityAwsIamAuthEvent {
|
||||
};
|
||||
}
|
||||
|
||||
interface GetIdentityAwsIamAuthEvent {
|
||||
type: EventType.GET_IDENTITY_AWS_IAM_AUTH;
|
||||
interface GetIdentityAwsAuthEvent {
|
||||
type: EventType.GET_IDENTITY_AWS_AUTH;
|
||||
metadata: {
|
||||
identityId: string;
|
||||
};
|
||||
@ -762,10 +762,10 @@ export type Event =
|
||||
| AddIdentityGcpAuthEvent
|
||||
| UpdateIdentityGcpAuthEvent
|
||||
| GetIdentityGcpAuthEvent
|
||||
| LoginIdentityAwsIamAuthEvent
|
||||
| AddIdentityAwsIamAuthEvent
|
||||
| UpdateIdentityAwsIamAuthEvent
|
||||
| GetIdentityAwsIamAuthEvent
|
||||
| LoginIdentityAwsAuthEvent
|
||||
| AddIdentityAwsAuthEvent
|
||||
| UpdateIdentityAwsAuthEvent
|
||||
| GetIdentityAwsAuthEvent
|
||||
| CreateEnvironmentEvent
|
||||
| UpdateEnvironmentEvent
|
||||
| DeleteEnvironmentEvent
|
||||
|
@ -92,7 +92,7 @@ export const UNIVERSAL_AUTH = {
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const AWS_IAM_AUTH = {
|
||||
export const AWS_AUTH = {
|
||||
LOGIN: {
|
||||
identityId: "The ID of the identity to login.",
|
||||
iamHttpRequestMethod: "The HTTP request method used in the signed request.",
|
||||
@ -288,7 +288,8 @@ export const RAW_SECRETS = {
|
||||
recursive:
|
||||
"Whether or not to fetch all secrets from the specified base path, and all of its subdirectories. Note, the max depth is 20 deep.",
|
||||
workspaceId: "The ID of the project to list secrets from.",
|
||||
workspaceSlug: "The slug of the project to list secrets from. This parameter is only usable by machine identities.",
|
||||
workspaceSlug:
|
||||
"The slug of the project to list secrets from. This parameter is only applicable by machine identities.",
|
||||
environment: "The slug of the environment to list secrets from.",
|
||||
secretPath: "The secret path to list secrets from.",
|
||||
includeImports: "Weather to include imported secrets or not."
|
||||
@ -307,6 +308,7 @@ export const RAW_SECRETS = {
|
||||
GET: {
|
||||
secretName: "The name of the secret to get.",
|
||||
workspaceId: "The ID of the project to get the secret from.",
|
||||
workspaceSlug: "The slug of the project to get the secret from.",
|
||||
environment: "The slug of the environment to get the secret from.",
|
||||
secretPath: "The path of the secret to get.",
|
||||
version: "The version of the secret to get.",
|
||||
@ -625,7 +627,8 @@ export const INTEGRATION = {
|
||||
shouldAutoRedeploy: "Used by Render to trigger auto deploy.",
|
||||
secretGCPLabel: "The label for GCP secrets.",
|
||||
secretAWSTag: "The tags for AWS secrets.",
|
||||
kmsKeyId: "The ID of the encryption key from AWS KMS."
|
||||
kmsKeyId: "The ID of the encryption key from AWS KMS.",
|
||||
shouldDisableDelete: "The flag to disable deletion of secrets in AWS Parameter Store."
|
||||
}
|
||||
},
|
||||
UPDATE: {
|
||||
|
@ -78,8 +78,8 @@ import { identityOrgDALFactory } from "@app/services/identity/identity-org-dal";
|
||||
import { identityServiceFactory } from "@app/services/identity/identity-service";
|
||||
import { identityAccessTokenDALFactory } from "@app/services/identity-access-token/identity-access-token-dal";
|
||||
import { identityAccessTokenServiceFactory } from "@app/services/identity-access-token/identity-access-token-service";
|
||||
import { identityAwsIamAuthDALFactory } from "@app/services/identity-aws-iam-auth/identity-aws-iam-auth-dal";
|
||||
import { identityAwsIamAuthServiceFactory } from "@app/services/identity-aws-iam-auth/identity-aws-iam-auth-service";
|
||||
import { identityAwsAuthDALFactory } from "@app/services/identity-aws-auth/identity-aws-auth-dal";
|
||||
import { identityAwsAuthServiceFactory } from "@app/services/identity-aws-auth/identity-aws-auth-service";
|
||||
import { identityGcpAuthDALFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-dal";
|
||||
import { identityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service";
|
||||
import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
||||
@ -205,7 +205,7 @@ export const registerRoutes = async (
|
||||
|
||||
const identityUaDAL = identityUaDALFactory(db);
|
||||
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
|
||||
const identityAwsIamAuthDAL = identityAwsIamAuthDALFactory(db);
|
||||
const identityAwsAuthDAL = identityAwsAuthDALFactory(db);
|
||||
|
||||
const identityGcpAuthDAL = identityGcpAuthDALFactory(db);
|
||||
|
||||
@ -716,9 +716,9 @@ export const registerRoutes = async (
|
||||
licenseService
|
||||
});
|
||||
|
||||
const identityAWSIAMAuthService = identityAwsIamAuthServiceFactory({
|
||||
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
||||
identityAccessTokenDAL,
|
||||
identityAwsIamAuthDAL,
|
||||
identityAwsAuthDAL,
|
||||
identityOrgMembershipDAL,
|
||||
identityDAL,
|
||||
licenseService,
|
||||
@ -794,7 +794,7 @@ export const registerRoutes = async (
|
||||
identityProject: identityProjectService,
|
||||
identityUa: identityUaService,
|
||||
identityGcpAuth: identityGcpAuthService,
|
||||
identityAwsIamAuth: identityAWSIAMAuthService,
|
||||
identityAwsAuth: identityAwsAuthService,
|
||||
secretApprovalPolicy: sapService,
|
||||
accessApprovalPolicy: accessApprovalPolicyService,
|
||||
accessApprovalRequest: accessApprovalRequestService,
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { IdentityAwsIamAuthsSchema } from "@app/db/schemas";
|
||||
import { IdentityAwsAuthsSchema } from "@app/db/schemas";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { AWS_IAM_AUTH } from "@app/lib/api-docs";
|
||||
import { AWS_AUTH } from "@app/lib/api-docs";
|
||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
@ -10,22 +10,22 @@ import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
|
||||
import {
|
||||
validateAccountIds,
|
||||
validatePrincipalArns
|
||||
} from "@app/services/identity-aws-iam-auth/identity-aws-iam-auth-validators";
|
||||
} from "@app/services/identity-aws-auth/identity-aws-auth-validators";
|
||||
|
||||
export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvider) => {
|
||||
export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/aws-iam-auth/login",
|
||||
url: "/aws-auth/login",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
schema: {
|
||||
description: "Login with AWS IAM Auth",
|
||||
description: "Login with AWS Auth",
|
||||
body: z.object({
|
||||
identityId: z.string().describe(AWS_IAM_AUTH.LOGIN.identityId),
|
||||
iamHttpRequestMethod: z.string().default("POST").describe(AWS_IAM_AUTH.LOGIN.iamHttpRequestMethod),
|
||||
iamRequestBody: z.string().describe(AWS_IAM_AUTH.LOGIN.iamRequestBody),
|
||||
iamRequestHeaders: z.string().describe(AWS_IAM_AUTH.LOGIN.iamRequestHeaders)
|
||||
identityId: z.string().describe(AWS_AUTH.LOGIN.identityId),
|
||||
iamHttpRequestMethod: z.string().default("POST").describe(AWS_AUTH.LOGIN.iamHttpRequestMethod),
|
||||
iamRequestBody: z.string().describe(AWS_AUTH.LOGIN.iamRequestBody),
|
||||
iamRequestHeaders: z.string().describe(AWS_AUTH.LOGIN.iamRequestHeaders)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@ -37,18 +37,18 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityAwsIamAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
await server.services.identityAwsIamAuth.login(req.body);
|
||||
const { identityAwsAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||
await server.services.identityAwsAuth.login(req.body);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg?.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_AWS_IAM_AUTH,
|
||||
type: EventType.LOGIN_IDENTITY_AWS_AUTH,
|
||||
metadata: {
|
||||
identityId: identityAwsIamAuth.identityId,
|
||||
identityId: identityAwsAuth.identityId,
|
||||
identityAccessTokenId: identityAccessToken.id,
|
||||
identityAwsIamAuthId: identityAwsIamAuth.id
|
||||
identityAwsAuthId: identityAwsAuth.id
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -56,21 +56,21 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
return {
|
||||
accessToken,
|
||||
tokenType: "Bearer" as const,
|
||||
expiresIn: identityAwsIamAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL
|
||||
expiresIn: identityAwsAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/aws-iam-auth/identities/:identityId",
|
||||
url: "/aws-auth/identities/:identityId",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Attach AWS IAM Auth configuration onto identity",
|
||||
description: "Attach AWS Auth configuration onto identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
@ -109,12 +109,12 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
identityAwsIamAuth: IdentityAwsIamAuthsSchema
|
||||
identityAwsAuth: IdentityAwsAuthsSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const identityAwsIamAuth = await server.services.identityAwsIamAuth.attachAwsIamAuth({
|
||||
const identityAwsAuth = await server.services.identityAwsAuth.attachAwsAuth({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
@ -125,35 +125,35 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityAwsIamAuth.orgId,
|
||||
orgId: identityAwsAuth.orgId,
|
||||
event: {
|
||||
type: EventType.ADD_IDENTITY_AWS_IAM_AUTH,
|
||||
type: EventType.ADD_IDENTITY_AWS_AUTH,
|
||||
metadata: {
|
||||
identityId: identityAwsIamAuth.identityId,
|
||||
stsEndpoint: identityAwsIamAuth.stsEndpoint,
|
||||
allowedPrincipalArns: identityAwsIamAuth.allowedPrincipalArns,
|
||||
allowedAccountIds: identityAwsIamAuth.allowedAccountIds,
|
||||
accessTokenTTL: identityAwsIamAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL,
|
||||
accessTokenTrustedIps: identityAwsIamAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||
accessTokenNumUsesLimit: identityAwsIamAuth.accessTokenNumUsesLimit
|
||||
identityId: identityAwsAuth.identityId,
|
||||
stsEndpoint: identityAwsAuth.stsEndpoint,
|
||||
allowedPrincipalArns: identityAwsAuth.allowedPrincipalArns,
|
||||
allowedAccountIds: identityAwsAuth.allowedAccountIds,
|
||||
accessTokenTTL: identityAwsAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||
accessTokenTrustedIps: identityAwsAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { identityAwsIamAuth };
|
||||
return { identityAwsAuth };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "PATCH",
|
||||
url: "/aws-iam-auth/identities/:identityId",
|
||||
url: "/aws-auth/identities/:identityId",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Update AWS IAM Auth configuration on identity",
|
||||
description: "Update AWS Auth configuration on identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
@ -185,12 +185,12 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
identityAwsIamAuth: IdentityAwsIamAuthsSchema
|
||||
identityAwsAuth: IdentityAwsAuthsSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const identityAwsIamAuth = await server.services.identityAwsIamAuth.updateAwsIamAuth({
|
||||
const identityAwsAuth = await server.services.identityAwsAuth.updateAwsAuth({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
@ -201,35 +201,35 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityAwsIamAuth.orgId,
|
||||
orgId: identityAwsAuth.orgId,
|
||||
event: {
|
||||
type: EventType.UPDATE_IDENTITY_AWS_IAM_AUTH,
|
||||
type: EventType.UPDATE_IDENTITY_AWS_AUTH,
|
||||
metadata: {
|
||||
identityId: identityAwsIamAuth.identityId,
|
||||
stsEndpoint: identityAwsIamAuth.stsEndpoint,
|
||||
allowedPrincipalArns: identityAwsIamAuth.allowedPrincipalArns,
|
||||
allowedAccountIds: identityAwsIamAuth.allowedAccountIds,
|
||||
accessTokenTTL: identityAwsIamAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL,
|
||||
accessTokenTrustedIps: identityAwsIamAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||
accessTokenNumUsesLimit: identityAwsIamAuth.accessTokenNumUsesLimit
|
||||
identityId: identityAwsAuth.identityId,
|
||||
stsEndpoint: identityAwsAuth.stsEndpoint,
|
||||
allowedPrincipalArns: identityAwsAuth.allowedPrincipalArns,
|
||||
allowedAccountIds: identityAwsAuth.allowedAccountIds,
|
||||
accessTokenTTL: identityAwsAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||
accessTokenTrustedIps: identityAwsAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { identityAwsIamAuth };
|
||||
return { identityAwsAuth };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/aws-iam-auth/identities/:identityId",
|
||||
url: "/aws-auth/identities/:identityId",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Retrieve AWS IAM Auth configuration on identity",
|
||||
description: "Retrieve AWS Auth configuration on identity",
|
||||
security: [
|
||||
{
|
||||
bearerAuth: []
|
||||
@ -240,12 +240,12 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
identityAwsIamAuth: IdentityAwsIamAuthsSchema
|
||||
identityAwsAuth: IdentityAwsAuthsSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const identityAwsIamAuth = await server.services.identityAwsIamAuth.getAwsIamAuth({
|
||||
const identityAwsAuth = await server.services.identityAwsAuth.getAwsAuth({
|
||||
identityId: req.params.identityId,
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
@ -255,15 +255,15 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityAwsIamAuth.orgId,
|
||||
orgId: identityAwsAuth.orgId,
|
||||
event: {
|
||||
type: EventType.GET_IDENTITY_AWS_IAM_AUTH,
|
||||
type: EventType.GET_IDENTITY_AWS_AUTH,
|
||||
metadata: {
|
||||
identityId: identityAwsIamAuth.identityId
|
||||
identityId: identityAwsAuth.identityId
|
||||
}
|
||||
}
|
||||
});
|
||||
return { identityAwsIamAuth };
|
||||
return { identityAwsAuth };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -2,7 +2,7 @@ import { registerAdminRouter } from "./admin-router";
|
||||
import { registerAuthRoutes } from "./auth-router";
|
||||
import { registerProjectBotRouter } from "./bot-router";
|
||||
import { registerIdentityAccessTokenRouter } from "./identity-access-token-router";
|
||||
import { registerIdentityAwsIamAuthRouter } from "./identity-aws-iam-auth-router";
|
||||
import { registerIdentityAwsAuthRouter } from "./identity-aws-iam-auth-router";
|
||||
import { registerIdentityGcpAuthRouter } from "./identity-gcp-auth-router";
|
||||
import { registerIdentityRouter } from "./identity-router";
|
||||
import { registerIdentityUaRouter } from "./identity-ua";
|
||||
@ -30,8 +30,9 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
||||
await authRouter.register(registerAuthRoutes);
|
||||
await authRouter.register(registerIdentityUaRouter);
|
||||
await authRouter.register(registerIdentityGcpAuthRouter);
|
||||
await authRouter.register(registerIdentityAwsIamAuthRouter);
|
||||
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||
await authRouter.register(registerIdentityAwsAuthRouter);
|
||||
},
|
||||
{ prefix: "/auth" }
|
||||
);
|
||||
|
@ -66,7 +66,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
||||
)
|
||||
.optional()
|
||||
.describe(INTEGRATION.CREATE.metadata.secretAWSTag),
|
||||
kmsKeyId: z.string().optional().describe(INTEGRATION.CREATE.metadata.kmsKeyId)
|
||||
kmsKeyId: z.string().optional().describe(INTEGRATION.CREATE.metadata.kmsKeyId),
|
||||
shouldDisableDelete: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldDisableDelete)
|
||||
})
|
||||
.default({})
|
||||
}),
|
||||
|
@ -293,6 +293,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}),
|
||||
querystring: z.object({
|
||||
workspaceId: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceId),
|
||||
workspaceSlug: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceSlug),
|
||||
environment: z.string().trim().optional().describe(RAW_SECRETS.GET.environment),
|
||||
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath),
|
||||
version: z.coerce.number().optional().describe(RAW_SECRETS.GET.version),
|
||||
@ -311,6 +312,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const { workspaceSlug } = req.query;
|
||||
let { secretPath, environment, workspaceId } = req.query;
|
||||
if (req.auth.actor === ActorType.SERVICE) {
|
||||
const scope = ServiceTokenScopes.parse(req.auth.serviceToken.scopes);
|
||||
@ -322,7 +324,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" });
|
||||
if (!environment) throw new BadRequestError({ message: "Missing environment" });
|
||||
if (!workspaceId && !workspaceSlug)
|
||||
throw new BadRequestError({ message: "You must provide workspaceSlug or workspaceId" });
|
||||
|
||||
const secret = await server.services.secret.getSecretByNameRaw({
|
||||
actorId: req.permission.id,
|
||||
@ -331,6 +335,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
actorOrgId: req.permission.orgId,
|
||||
environment,
|
||||
projectId: workspaceId,
|
||||
projectSlug: workspaceSlug,
|
||||
path: secretPath,
|
||||
secretName: req.params.secretName,
|
||||
type: req.query.type,
|
||||
@ -339,7 +344,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId: req.query.workspaceId,
|
||||
projectId: secret.workspace,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.GET_SECRET,
|
||||
@ -358,7 +363,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId,
|
||||
workspaceId: secret.workspace,
|
||||
environment,
|
||||
secretPath: req.query.secretPath,
|
||||
channel: getUserAgentType(req.headers["user-agent"]),
|
||||
|
@ -0,0 +1,11 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TIdentityAwsAuthDALFactory = ReturnType<typeof identityAwsAuthDALFactory>;
|
||||
|
||||
export const identityAwsAuthDALFactory = (db: TDbClient) => {
|
||||
const awsAuthOrm = ormify(db, TableName.IdentityAwsAuth);
|
||||
|
||||
return awsAuthOrm;
|
||||
};
|
@ -16,48 +16,43 @@ import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
|
||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||
import { TIdentityAwsIamAuthDALFactory } from "./identity-aws-iam-auth-dal";
|
||||
import { extractPrincipalArn } from "./identity-aws-iam-auth-fns";
|
||||
import { TIdentityAwsAuthDALFactory } from "./identity-aws-auth-dal";
|
||||
import { extractPrincipalArn } from "./identity-aws-auth-fns";
|
||||
import {
|
||||
TAttachAWSIAMAuthDTO,
|
||||
TAWSGetCallerIdentityHeaders,
|
||||
TGetAWSIAMAuthDTO,
|
||||
TAttachAwsAuthDTO,
|
||||
TAwsGetCallerIdentityHeaders,
|
||||
TGetAwsAuthDTO,
|
||||
TGetCallerIdentityResponse,
|
||||
TLoginAWSIAMAuthDTO,
|
||||
TUpdateAWSIAMAuthDTO
|
||||
} from "./identity-aws-iam-auth-types";
|
||||
TLoginAwsAuthDTO,
|
||||
TUpdateAwsAuthDTO
|
||||
} from "./identity-aws-auth-types";
|
||||
|
||||
type TIdentityAwsIamAuthServiceFactoryDep = {
|
||||
type TIdentityAwsAuthServiceFactoryDep = {
|
||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create">;
|
||||
identityAwsIamAuthDAL: Pick<TIdentityAwsIamAuthDALFactory, "findOne" | "transaction" | "create" | "updateById">;
|
||||
identityAwsAuthDAL: Pick<TIdentityAwsAuthDALFactory, "findOne" | "transaction" | "create" | "updateById">;
|
||||
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
||||
identityDAL: Pick<TIdentityDALFactory, "updateById">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
};
|
||||
|
||||
export type TIdentityAwsIamAuthServiceFactory = ReturnType<typeof identityAwsIamAuthServiceFactory>;
|
||||
export type TIdentityAwsAuthServiceFactory = ReturnType<typeof identityAwsAuthServiceFactory>;
|
||||
|
||||
export const identityAwsIamAuthServiceFactory = ({
|
||||
export const identityAwsAuthServiceFactory = ({
|
||||
identityAccessTokenDAL,
|
||||
identityAwsIamAuthDAL,
|
||||
identityAwsAuthDAL,
|
||||
identityOrgMembershipDAL,
|
||||
identityDAL,
|
||||
licenseService,
|
||||
permissionService
|
||||
}: TIdentityAwsIamAuthServiceFactoryDep) => {
|
||||
const login = async ({
|
||||
identityId,
|
||||
iamHttpRequestMethod,
|
||||
iamRequestBody,
|
||||
iamRequestHeaders
|
||||
}: TLoginAWSIAMAuthDTO) => {
|
||||
const identityAwsIamAuth = await identityAwsIamAuthDAL.findOne({ identityId });
|
||||
if (!identityAwsIamAuth) throw new UnauthorizedError();
|
||||
}: TIdentityAwsAuthServiceFactoryDep) => {
|
||||
const login = async ({ identityId, iamHttpRequestMethod, iamRequestBody, iamRequestHeaders }: TLoginAwsAuthDTO) => {
|
||||
const identityAwsAuth = await identityAwsAuthDAL.findOne({ identityId });
|
||||
if (!identityAwsAuth) throw new UnauthorizedError();
|
||||
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityAwsIamAuth.identityId });
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityAwsAuth.identityId });
|
||||
|
||||
const headers: TAWSGetCallerIdentityHeaders = JSON.parse(Buffer.from(iamRequestHeaders, "base64").toString());
|
||||
const headers: TAwsGetCallerIdentityHeaders = JSON.parse(Buffer.from(iamRequestHeaders, "base64").toString());
|
||||
const body: string = Buffer.from(iamRequestBody, "base64").toString();
|
||||
|
||||
const {
|
||||
@ -68,15 +63,15 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
}
|
||||
}: { data: TGetCallerIdentityResponse } = await axios({
|
||||
method: iamHttpRequestMethod,
|
||||
url: identityAwsIamAuth.stsEndpoint,
|
||||
url: identityAwsAuth.stsEndpoint,
|
||||
headers,
|
||||
data: body
|
||||
});
|
||||
|
||||
if (identityAwsIamAuth.allowedAccountIds) {
|
||||
if (identityAwsAuth.allowedAccountIds) {
|
||||
// validate if Account is in the list of allowed Account IDs
|
||||
|
||||
const isAccountAllowed = identityAwsIamAuth.allowedAccountIds
|
||||
const isAccountAllowed = identityAwsAuth.allowedAccountIds
|
||||
.split(",")
|
||||
.map((accountId) => accountId.trim())
|
||||
.some((accountId) => accountId === Account);
|
||||
@ -84,10 +79,10 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
if (!isAccountAllowed) throw new UnauthorizedError();
|
||||
}
|
||||
|
||||
if (identityAwsIamAuth.allowedPrincipalArns) {
|
||||
if (identityAwsAuth.allowedPrincipalArns) {
|
||||
// validate if Arn is in the list of allowed Principal ARNs
|
||||
|
||||
const isArnAllowed = identityAwsIamAuth.allowedPrincipalArns
|
||||
const isArnAllowed = identityAwsAuth.allowedPrincipalArns
|
||||
.split(",")
|
||||
.map((principalArn) => principalArn.trim())
|
||||
.some((principalArn) => {
|
||||
@ -100,15 +95,15 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
if (!isArnAllowed) throw new UnauthorizedError();
|
||||
}
|
||||
|
||||
const identityAccessToken = await identityAwsIamAuthDAL.transaction(async (tx) => {
|
||||
const identityAccessToken = await identityAwsAuthDAL.transaction(async (tx) => {
|
||||
const newToken = await identityAccessTokenDAL.create(
|
||||
{
|
||||
identityId: identityAwsIamAuth.identityId,
|
||||
identityId: identityAwsAuth.identityId,
|
||||
isAccessTokenRevoked: false,
|
||||
accessTokenTTL: identityAwsIamAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL,
|
||||
accessTokenTTL: identityAwsAuth.accessTokenTTL,
|
||||
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||
accessTokenNumUses: 0,
|
||||
accessTokenNumUsesLimit: identityAwsIamAuth.accessTokenNumUsesLimit
|
||||
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit
|
||||
},
|
||||
tx
|
||||
);
|
||||
@ -118,7 +113,7 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
const appCfg = getConfig();
|
||||
const accessToken = jwt.sign(
|
||||
{
|
||||
identityId: identityAwsIamAuth.identityId,
|
||||
identityId: identityAwsAuth.identityId,
|
||||
identityAccessTokenId: identityAccessToken.id,
|
||||
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
||||
} as TIdentityAccessTokenJwtPayload,
|
||||
@ -131,10 +126,10 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
}
|
||||
);
|
||||
|
||||
return { accessToken, identityAwsIamAuth, identityAccessToken, identityMembershipOrg };
|
||||
return { accessToken, identityAwsAuth, identityAccessToken, identityMembershipOrg };
|
||||
};
|
||||
|
||||
const attachAwsIamAuth = async ({
|
||||
const attachAwsAuth = async ({
|
||||
identityId,
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
@ -147,12 +142,12 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actor,
|
||||
actorOrgId
|
||||
}: TAttachAWSIAMAuthDTO) => {
|
||||
}: TAttachAwsAuthDTO) => {
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
||||
if (identityMembershipOrg.identity.authMethod)
|
||||
throw new BadRequestError({
|
||||
message: "Failed to add AWS IAM Auth to already configured identity"
|
||||
message: "Failed to add AWS Auth to already configured identity"
|
||||
});
|
||||
|
||||
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
||||
@ -186,10 +181,11 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||
});
|
||||
|
||||
const identityAwsIamAuth = await identityAwsIamAuthDAL.transaction(async (tx) => {
|
||||
const doc = await identityAwsIamAuthDAL.create(
|
||||
const identityAwsAuth = await identityAwsAuthDAL.transaction(async (tx) => {
|
||||
const doc = await identityAwsAuthDAL.create(
|
||||
{
|
||||
identityId: identityMembershipOrg.identityId,
|
||||
type: "iam",
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
allowedAccountIds,
|
||||
@ -203,16 +199,16 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
await identityDAL.updateById(
|
||||
identityMembershipOrg.identityId,
|
||||
{
|
||||
authMethod: IdentityAuthMethod.AWS_IAM_AUTH
|
||||
authMethod: IdentityAuthMethod.AWS_AUTH
|
||||
},
|
||||
tx
|
||||
);
|
||||
return doc;
|
||||
});
|
||||
return { ...identityAwsIamAuth, orgId: identityMembershipOrg.orgId };
|
||||
return { ...identityAwsAuth, orgId: identityMembershipOrg.orgId };
|
||||
};
|
||||
|
||||
const updateAwsIamAuth = async ({
|
||||
const updateAwsAuth = async ({
|
||||
identityId,
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
@ -225,20 +221,19 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
actor,
|
||||
actorOrgId
|
||||
}: TUpdateAWSIAMAuthDTO) => {
|
||||
}: TUpdateAwsAuthDTO) => {
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
||||
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_IAM_AUTH)
|
||||
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_AUTH)
|
||||
throw new BadRequestError({
|
||||
message: "Failed to update AWS IAM Auth"
|
||||
message: "Failed to update AWS Auth"
|
||||
});
|
||||
|
||||
const identityAwsIamAuth = await identityAwsIamAuthDAL.findOne({ identityId });
|
||||
const identityAwsAuth = await identityAwsAuthDAL.findOne({ identityId });
|
||||
|
||||
if (
|
||||
(accessTokenMaxTTL || identityAwsIamAuth.accessTokenMaxTTL) > 0 &&
|
||||
(accessTokenTTL || identityAwsIamAuth.accessTokenMaxTTL) >
|
||||
(accessTokenMaxTTL || identityAwsIamAuth.accessTokenMaxTTL)
|
||||
(accessTokenMaxTTL || identityAwsAuth.accessTokenMaxTTL) > 0 &&
|
||||
(accessTokenTTL || identityAwsAuth.accessTokenMaxTTL) > (accessTokenMaxTTL || identityAwsAuth.accessTokenMaxTTL)
|
||||
) {
|
||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||
}
|
||||
@ -270,7 +265,7 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||
});
|
||||
|
||||
const updatedAwsIamAuth = await identityAwsIamAuthDAL.updateById(identityAwsIamAuth.id, {
|
||||
const updatedAwsAuth = await identityAwsAuthDAL.updateById(identityAwsAuth.id, {
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
allowedAccountIds,
|
||||
@ -282,18 +277,18 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
: undefined
|
||||
});
|
||||
|
||||
return { ...updatedAwsIamAuth, orgId: identityMembershipOrg.orgId };
|
||||
return { ...updatedAwsAuth, orgId: identityMembershipOrg.orgId };
|
||||
};
|
||||
|
||||
const getAwsIamAuth = async ({ identityId, actorId, actor, actorAuthMethod, actorOrgId }: TGetAWSIAMAuthDTO) => {
|
||||
const getAwsAuth = async ({ identityId, actorId, actor, actorAuthMethod, actorOrgId }: TGetAwsAuthDTO) => {
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
||||
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_IAM_AUTH)
|
||||
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.AWS_AUTH)
|
||||
throw new BadRequestError({
|
||||
message: "The identity does not have AWS IAM Auth attached"
|
||||
message: "The identity does not have AWS Auth attached"
|
||||
});
|
||||
|
||||
const awsIamIdentityAuth = await identityAwsIamAuthDAL.findOne({ identityId });
|
||||
const awsIdentityAuth = await identityAwsAuthDAL.findOne({ identityId });
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor,
|
||||
@ -303,13 +298,13 @@ export const identityAwsIamAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
|
||||
return { ...awsIamIdentityAuth, orgId: identityMembershipOrg.orgId };
|
||||
return { ...awsIdentityAuth, orgId: identityMembershipOrg.orgId };
|
||||
};
|
||||
|
||||
return {
|
||||
login,
|
||||
attachAwsIamAuth,
|
||||
updateAwsIamAuth,
|
||||
getAwsIamAuth
|
||||
attachAwsAuth,
|
||||
updateAwsAuth,
|
||||
getAwsAuth
|
||||
};
|
||||
};
|
@ -1,13 +1,13 @@
|
||||
import { TProjectPermission } from "@app/lib/types";
|
||||
|
||||
export type TLoginAWSIAMAuthDTO = {
|
||||
export type TLoginAwsAuthDTO = {
|
||||
identityId: string;
|
||||
iamHttpRequestMethod: string;
|
||||
iamRequestBody: string;
|
||||
iamRequestHeaders: string;
|
||||
};
|
||||
|
||||
export type TAttachAWSIAMAuthDTO = {
|
||||
export type TAttachAwsAuthDTO = {
|
||||
identityId: string;
|
||||
stsEndpoint: string;
|
||||
allowedPrincipalArns: string;
|
||||
@ -18,7 +18,7 @@ export type TAttachAWSIAMAuthDTO = {
|
||||
accessTokenTrustedIps: { ipAddress: string }[];
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TUpdateAWSIAMAuthDTO = {
|
||||
export type TUpdateAwsAuthDTO = {
|
||||
identityId: string;
|
||||
stsEndpoint?: string;
|
||||
allowedPrincipalArns?: string;
|
||||
@ -29,11 +29,11 @@ export type TUpdateAWSIAMAuthDTO = {
|
||||
accessTokenTrustedIps?: { ipAddress: string }[];
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TGetAWSIAMAuthDTO = {
|
||||
export type TGetAwsAuthDTO = {
|
||||
identityId: string;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TAWSGetCallerIdentityHeaders = {
|
||||
export type TAwsGetCallerIdentityHeaders = {
|
||||
"Content-Type": string;
|
||||
Host: string;
|
||||
"X-Amz-Date": string;
|
@ -1,11 +0,0 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TIdentityAwsIamAuthDALFactory = ReturnType<typeof identityAwsIamAuthDALFactory>;
|
||||
|
||||
export const identityAwsIamAuthDALFactory = (db: TDbClient) => {
|
||||
const awsIamAuthOrm = ormify(db, TableName.IdentityAwsIamAuth);
|
||||
|
||||
return awsIamAuthOrm;
|
||||
};
|
@ -52,7 +52,7 @@ export const identityUaServiceFactory = ({
|
||||
}: TIdentityUaServiceFactoryDep) => {
|
||||
const login = async (clientId: string, clientSecret: string, ip: string) => {
|
||||
const identityUa = await identityUaDAL.findOne({ clientId });
|
||||
if (!identityUa) throw new UnauthorizedError();
|
||||
if (!identityUa) throw new UnauthorizedError({ message: "Invalid credentials" });
|
||||
|
||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityUa.identityId });
|
||||
|
||||
@ -68,7 +68,7 @@ export const identityUaServiceFactory = ({
|
||||
const validClientSecretInfo = clientSecrtInfo.find(({ clientSecretHash }) =>
|
||||
bcrypt.compareSync(clientSecret, clientSecretHash)
|
||||
);
|
||||
if (!validClientSecretInfo) throw new UnauthorizedError();
|
||||
if (!validClientSecretInfo) throw new UnauthorizedError({ message: "Invalid credentials" });
|
||||
|
||||
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
|
||||
if (Number(clientSecretTTL) > 0) {
|
||||
|
@ -517,20 +517,22 @@ const syncSecretsAWSParameterStore = async ({
|
||||
})
|
||||
);
|
||||
|
||||
// Identify secrets to delete
|
||||
await Promise.all(
|
||||
Object.keys(awsParameterStoreSecretsObj).map(async (key) => {
|
||||
if (!(key in secrets)) {
|
||||
// case:
|
||||
// -> delete secret
|
||||
await ssm
|
||||
.deleteParameter({
|
||||
Name: awsParameterStoreSecretsObj[key].Name as string
|
||||
})
|
||||
.promise();
|
||||
}
|
||||
})
|
||||
);
|
||||
if (!metadata.shouldDisableDelete) {
|
||||
// Identify secrets to delete
|
||||
await Promise.all(
|
||||
Object.keys(awsParameterStoreSecretsObj).map(async (key) => {
|
||||
if (!(key in secrets)) {
|
||||
// case:
|
||||
// -> delete secret
|
||||
await ssm
|
||||
.deleteParameter({
|
||||
Name: awsParameterStoreSecretsObj[key].Name as string
|
||||
})
|
||||
.promise();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -27,6 +27,7 @@ export type TCreateIntegrationDTO = {
|
||||
value: string;
|
||||
}[];
|
||||
kmsKeyId?: string;
|
||||
shouldDisableDelete?: boolean;
|
||||
};
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
|
@ -546,6 +546,10 @@ export const orgServiceFactory = ({
|
||||
code
|
||||
});
|
||||
|
||||
await userDAL.updateById(user.id, {
|
||||
isEmailVerified: true
|
||||
});
|
||||
|
||||
if (user.isAccepted) {
|
||||
// this means user has already completed signup process
|
||||
// isAccepted is set true when keys are exchanged
|
||||
|
@ -972,7 +972,8 @@ export const secretServiceFactory = ({
|
||||
path,
|
||||
actor,
|
||||
environment,
|
||||
projectId,
|
||||
projectId: workspaceId,
|
||||
projectSlug,
|
||||
actorId,
|
||||
actorOrgId,
|
||||
actorAuthMethod,
|
||||
@ -980,6 +981,8 @@ export const secretServiceFactory = ({
|
||||
includeImports,
|
||||
version
|
||||
}: TGetASecretRawDTO) => {
|
||||
const projectId = workspaceId || (await projectDAL.findProjectBySlug(projectSlug as string, actorOrgId)).id;
|
||||
|
||||
const botKey = await projectBotService.getBotKey(projectId);
|
||||
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
|
||||
|
||||
|
@ -152,7 +152,9 @@ export type TGetASecretRawDTO = {
|
||||
type: "shared" | "personal";
|
||||
includeImports?: boolean;
|
||||
version?: number;
|
||||
} & TProjectPermission;
|
||||
projectSlug?: string;
|
||||
projectId?: string;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TCreateSecretRawDTO = TProjectPermission & {
|
||||
secretPath: string;
|
||||
|
@ -51,7 +51,7 @@ As a result, the 3 main concepts that are important to understand are:
|
||||
|
||||
- **[Identities](/documentation/platform/identities/overview)**: users or machines with a set permissions assigned to them.
|
||||
- **[Clients](/integrations/platforms/kubernetes)**: Infisical-developed tools for managing secrets in various infrastructure components (e.g., [Kubernetes Operator](/integrations/platforms/kubernetes), [Infisical Agent](/integrations/platforms/infisical-agent), [CLI](/cli/usage), [SDKs](/sdks/overview), [API](/api-reference/overview/introduction), [Web Dashboard](/documentation/platform/organization)).
|
||||
- **[Authentication Methods](/documentation/platform/identities/universal-auth)**: ways for Identities to authenticate inside different clients (e.g., SAML SSO for Web Dashboard, Universal Auth for Infisical Agent, AWS IAM Auth etc.).
|
||||
- **[Authentication Methods](/documentation/platform/identities/universal-auth)**: ways for Identities to authenticate inside different clients (e.g., SAML SSO for Web Dashboard, Universal Auth for Infisical Agent, AWS Auth etc.).
|
||||
|
||||
## How to get started with Infisical?
|
||||
|
||||
|
@ -1,34 +1,60 @@
|
||||
---
|
||||
title: AWS IAM Auth
|
||||
title: AWS Auth
|
||||
description: "Learn how to authenticate with Infisical for EC2 instances, Lambda functions, and other IAM principals."
|
||||
---
|
||||
|
||||
**AWS IAM Auth** is an AWS-native authentication method for IAM principals like EC2 instances or Lambda functions to access Infisical.
|
||||
**AWS Auth** is an AWS-native authentication method for IAM principals like EC2 instances or Lambda functions to access Infisical.
|
||||
|
||||
## Diagram
|
||||
|
||||
The following sequence digram illustrates the AWS Auth workflow for authenticating AWS IAM principals with Infisical.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as Client
|
||||
participant Infis as Infisical
|
||||
participant AWS as AWS STS
|
||||
|
||||
Note over Client,Client: Step 1: Sign GetCallerIdentityQuery
|
||||
|
||||
Note over Client,Infis: Step 2: Login Operation
|
||||
Client->>Infis: Send signed query details /api/v1/auth/aws-auth/login
|
||||
|
||||
Note over Infis,AWS: Step 3: Query verification
|
||||
Infis->>AWS: Forward signed GetCallerIdentity query
|
||||
AWS-->>Infis: Return IAM user/role details
|
||||
|
||||
Note over Infis: Step 4: Identity Property Validation
|
||||
Infis->>Client: Return short-lived access token
|
||||
|
||||
Note over Client,Infis: Step 4: Access Infisical API with Token
|
||||
Client->>Infis: Make authenticated requests using the short-lived access token
|
||||
```
|
||||
|
||||
## Concept
|
||||
|
||||
At a high-level, Infisical authenticates an IAM principal by verifying its identity and checking that it meets specific requirements (e.g. it is an allowed IAM principal ARN) at the `/api/v1/auth/aws-iam-auth/login` endpoint. If successful,
|
||||
At a high-level, Infisical authenticates an IAM principal by verifying its identity and checking that it meets specific requirements (e.g. it is an allowed IAM principal ARN) at the `/api/v1/auth/aws-auth/login` endpoint. If successful,
|
||||
then Infisical returns a short-lived access token that can be used to make authenticated requests to the Infisical API.
|
||||
|
||||
In AWS IAM Auth, an IAM principal signs a `GetCallerIdentity` query using the [AWS Signature v4 algorithm](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html); this is done using the credentials from the AWS environment where the IAM principal is running.
|
||||
In AWS Auth, an IAM principal signs a `GetCallerIdentity` query using the [AWS Signature v4 algorithm](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html); this is done using the credentials from the AWS environment where the IAM principal is running.
|
||||
The query data including the request method, request body, and request headers are sent to Infisical afterwhich Infisical forwards the signed query to AWS STS API via the [sts:GetCallerIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html) method to verify and obtain the identity of the IAM principal.
|
||||
Once obtained, the identity information is verified against specified requirements such as if the associated IAM principal ARN is allowed to authenticate with Infisical. If all is well, Infisical returns a short-lived access token that can be used to make authenticated requests to the Infisical API.
|
||||
|
||||
<Note>
|
||||
We recommend using one of Infisical's clients like SDKs or the Infisical Agent
|
||||
to authenticate with Infisical using AWS IAM Auth as they handle the
|
||||
to authenticate with Infisical using AWS Auth as they handle the
|
||||
authentication process including the signed `GetCallerIdentity` query
|
||||
construction for you.
|
||||
|
||||
Also, note that Infisical needs network-level access to send requests to the AWS STS API
|
||||
as part of the AWS IAM Auth workflow.
|
||||
as part of the AWS Auth workflow.
|
||||
|
||||
</Note>
|
||||
|
||||
## Workflow
|
||||
|
||||
In the following steps, we explore how to create and use identities for your workloads and applications on AWS to
|
||||
access the Infisical API using the AWS IAM authentication method.
|
||||
access the Infisical API using the AWS Auth authentication method.
|
||||
|
||||
<Steps>
|
||||
<Step title="Creating an identity">
|
||||
@ -45,9 +71,9 @@ access the Infisical API using the AWS IAM authentication method.
|
||||
- Name (required): A friendly name for the identity.
|
||||
- Role (required): A role from the **Organization Roles** tab for the identity to assume. The organization role assigned will determine what organization level resources this identity can have access to.
|
||||
|
||||
Once you've created an identity, you'll be prompted to configure the authentication method for it. Here, select **AWS IAM Auth**.
|
||||
Once you've created an identity, you'll be prompted to configure the authentication method for it. Here, select **AWS Auth**.
|
||||
|
||||

|
||||

|
||||
|
||||
Here's some more guidance on each field:
|
||||
|
||||
@ -71,7 +97,7 @@ access the Infisical API using the AWS IAM authentication method.
|
||||

|
||||
</Step>
|
||||
<Step title="Accessing the Infisical API with the identity">
|
||||
To access the Infisical API as the identity, you need to construct a signed `GetCallerIdentity` query using the [AWS Signature v4 algorithm](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html) and make a request to the `/api/v1/auth/aws-iam-auth/login` endpoint containing the query data
|
||||
To access the Infisical API as the identity, you need to construct a signed `GetCallerIdentity` query using the [AWS Signature v4 algorithm](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html) and make a request to the `/api/v1/auth/aws-auth/login` endpoint containing the query data
|
||||
in exchange for an access token.
|
||||
|
||||
We provide a few code examples below of how you can authenticate with Infisical from inside a Lambda function, EC2 instance, etc. and obtain an access token to access the [Infisical API](/api-reference/overview/introduction).
|
||||
@ -119,7 +145,7 @@ access the Infisical API using the AWS IAM authentication method.
|
||||
const identityId = "<your-identity-id>";
|
||||
|
||||
const { data } = await axios.post(
|
||||
`${infisicalUrl}/api/v1/auth/aws-iam-auth/login`,
|
||||
`${infisicalUrl}/api/v1/auth/aws-auth/login`,
|
||||
{
|
||||
identityId,
|
||||
iamHttpRequestMethod: "POST",
|
||||
@ -191,7 +217,7 @@ access the Infisical API using the AWS IAM authentication method.
|
||||
const infisicalUrl = "https://app.infisical.com"; // or your self-hosted Infisical URL
|
||||
const identityId = "<your-identity-id>";
|
||||
|
||||
const { data } = await axios.post(`${infisicalUrl}/api/v1/auth/aws-iam-auth/login`, {
|
||||
const { data } = await axios.post(`${infisicalUrl}/api/v1/auth/aws-auth/login`, {
|
||||
identityId,
|
||||
iamHttpRequestMethod: "POST",
|
||||
iamRequestUrl: Buffer.from(iamRequestURL).toString("base64"),
|
||||
@ -239,7 +265,7 @@ access the Infisical API using the AWS IAM authentication method.
|
||||
#### Sample request
|
||||
|
||||
```bash Request
|
||||
curl --location --request POST 'https://app.infisical.com/api/v1/auth/aws-iam-auth/login' \
|
||||
curl --location --request POST 'https://app.infisical.com/api/v1/auth/aws-auth/login' \
|
||||
--header 'Content-Type: application/x-www-form-urlencoded' \
|
||||
--data-urlencode 'identityId=...' \
|
||||
--data-urlencode 'iamHttpRequestMethod=...' \
|
||||
@ -263,7 +289,7 @@ access the Infisical API using the AWS IAM authentication method.
|
||||
</AccordionGroup>
|
||||
|
||||
<Tip>
|
||||
We recommend using one of Infisical's clients like SDKs or the Infisical Agent to authenticate with Infisical using AWS IAM Auth as they handle the authentication process including the signed `GetCallerIdentity` query construction for you.
|
||||
We recommend using one of Infisical's clients like SDKs or the Infisical Agent to authenticate with Infisical using AWS Auth as they handle the authentication process including the signed `GetCallerIdentity` query construction for you.
|
||||
</Tip>
|
||||
|
||||
<Note>
|
@ -7,7 +7,7 @@ description: "Learn how to use Machine Identities to programmatically interact w
|
||||
|
||||
An Infisical machine identity is an entity that represents a workload or application that require access to various resources in Infisical. This is conceptually similar to an IAM user in AWS or service account in Google Cloud Platform (GCP).
|
||||
|
||||
Each identity must authenticate with the Infisical API using a supported authentication method like [Universal Auth](/documentation/platform/identities/universal-auth), [AWS IAM Auth](/documentation/platform/identities/aws-iam-auth), or [GCP IAM Auth](/documentation/platform/identities/gcp-auth) to get back a short-lived access token to be used in subsequent requests.
|
||||
Each identity must authenticate with the Infisical API using a supported authentication method like [Universal Auth](/documentation/platform/identities/universal-auth), [AWS Auth](/documentation/platform/identities/aws-auth), or [GCP Auth](/documentation/platform/identities/gcp-auth) to get back a short-lived access token to be used in subsequent requests.
|
||||
|
||||

|
||||
|
||||
@ -38,8 +38,8 @@ Machine Identity support for the rest of the clients is planned to be released i
|
||||
To interact with various resources in Infisical, Machine Identities are able to authenticate using:
|
||||
|
||||
- [Universal Auth](/documentation/platform/identities/universal-auth): A platform-agnostic authentication method that can be configured on an identity suitable to authenticate from any platform/environment.
|
||||
- [AWS IAM Auth](/documentation/platform/identities/aws-iam-auth): An AWS-native authentication method for IAM principals like EC2 instances or Lambda functions to authenticate with Infisical.
|
||||
- [GCP IAM Auth](/documentation/platform/identities/gcp-auth): A GCP-native authentication method for IAM service accounts to authenticate with Infisical.
|
||||
- [AWS Auth](/documentation/platform/identities/aws-auth): An AWS-native authentication method for IAM principals like EC2 instances or Lambda functions to authenticate with Infisical.
|
||||
- [GCP Auth](/documentation/platform/identities/gcp-auth): A GCP-native authentication method for IAM service accounts and GCE instances to authenticate with Infisical.
|
||||
|
||||
## FAQ
|
||||
|
||||
|
@ -5,6 +5,25 @@ description: "Learn how to authenticate to Infisical from any platform or enviro
|
||||
|
||||
**Universal Auth** is a platform-agnostic authentication method that can be configured for a [machine identity](/documentation/platform/identities/machine-identities) suitable to authenticate from any platform/environment.
|
||||
|
||||
## Diagram
|
||||
|
||||
The following sequence digram illustrates the Universal Auth workflow for authenticating clients with Infisical.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as Client
|
||||
participant Infis as Infisical
|
||||
|
||||
Note over Client,Infis: Step 1: Login Operation
|
||||
Client->>Infis: Send Client ID and Client Secret
|
||||
|
||||
Note over Infis: Step 2: Client ID and Client Secret validation
|
||||
Infis->>Client: Return short-lived access token
|
||||
|
||||
Note over Client,Infis: Step 3: Access Infisical API with Token
|
||||
Client->>Infis: Make authenticated requests using the short-lived access token
|
||||
```
|
||||
|
||||
## Concept
|
||||
|
||||
In this method, Infisical authenticates an identity by verifying the credentials issued for it at the `/api/v1/auth/universal-auth/login` endpoint. If successful,
|
||||
@ -12,7 +31,7 @@ then Infisical returns a short-lived access token that can be used to make authe
|
||||
|
||||
In Universal Auth, an identity is given a **Client ID** and one or more **Client Secret(s)**. Together, a **Client ID** and **Client Secret** can be exchanged for a short-lived access token to authenticate with the Infisical API.
|
||||
|
||||
## Workflow
|
||||
## Guide
|
||||
|
||||
In the following steps, we explore how to create and use identities for your workloads and applications to access the Infisical API
|
||||
using the Universal Auth authentication method.
|
||||
|
Before Width: | Height: | Size: 538 KiB After Width: | Height: | Size: 538 KiB |
@ -77,6 +77,8 @@ spec:
|
||||
projectSlug: <project-slug>
|
||||
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
||||
secretsPath: "<secrets-path>" # Root is "/"
|
||||
recursive: true # Fetch all secrets from the specified path and all sub-directories. Default is false.
|
||||
|
||||
credentialsRef:
|
||||
secretName: universal-auth-credentials
|
||||
secretNamespace: default
|
||||
@ -89,6 +91,7 @@ spec:
|
||||
secretsScope:
|
||||
envSlug: <env-slug>
|
||||
secretsPath: <secrets-path> # Root is "/"
|
||||
recursive: true # Fetch all secrets from the specified path and all sub-directories. Default is false.
|
||||
|
||||
managedSecretReference:
|
||||
secretName: managed-secret
|
||||
|
@ -153,8 +153,8 @@
|
||||
"documentation/platform/auth-methods/email-password",
|
||||
"documentation/platform/token",
|
||||
"documentation/platform/identities/universal-auth",
|
||||
"documentation/platform/identities/aws-iam-auth",
|
||||
"documentation/platform/identities/gcp-auth",
|
||||
"documentation/platform/identities/aws-auth",
|
||||
"documentation/platform/mfa",
|
||||
{
|
||||
"group": "SSO",
|
||||
|
@ -31,6 +31,7 @@ export const SecretPathInput = ({
|
||||
const [inputValue, setInputValue] = useState(propValue ?? "");
|
||||
const [secretPath, setSecretPath] = useState("/");
|
||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||
const [isInputFocused, setIsInputFocus] = useState(false);
|
||||
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||
const debouncedInputValue = useDebounce(inputValue, 200);
|
||||
|
||||
@ -55,7 +56,9 @@ export const SecretPathInput = ({
|
||||
) {
|
||||
setSecretPath(debouncedInputValue);
|
||||
}
|
||||
}, [debouncedInputValue]);
|
||||
|
||||
useEffect(() => {
|
||||
// filter suggestions based on matching
|
||||
const searchFragment = debouncedInputValue.split("/").pop() || "";
|
||||
const filteredSuggestions = folders
|
||||
@ -65,7 +68,7 @@ export const SecretPathInput = ({
|
||||
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
||||
|
||||
setSuggestions(filteredSuggestions);
|
||||
}, [debouncedInputValue]);
|
||||
}, [debouncedInputValue, folders]);
|
||||
|
||||
const handleSuggestionSelect = (selectedIndex: number) => {
|
||||
if (!suggestions[selectedIndex]) {
|
||||
@ -75,7 +78,7 @@ export const SecretPathInput = ({
|
||||
const validPaths = inputValue.split("/");
|
||||
validPaths.pop();
|
||||
|
||||
const newValue = `${validPaths.join("/")}/${suggestions[selectedIndex]}`;
|
||||
const newValue = `${validPaths.join("/")}/${suggestions[selectedIndex]}/`;
|
||||
onChange?.(newValue);
|
||||
setInputValue(newValue);
|
||||
setSecretPath(newValue);
|
||||
@ -108,7 +111,7 @@ export const SecretPathInput = ({
|
||||
|
||||
return (
|
||||
<Popover.Root
|
||||
open={suggestions.length > 0 && inputValue.length > 1}
|
||||
open={suggestions.length > 0 && isInputFocused}
|
||||
onOpenChange={() => {
|
||||
setHighlightedIndex(-1);
|
||||
}}
|
||||
@ -119,6 +122,8 @@ export const SecretPathInput = ({
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={() => setIsInputFocus(true)}
|
||||
onBlur={() => setIsInputFocus(false)}
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
className={containerClassName}
|
||||
@ -150,8 +155,9 @@ export const SecretPathInput = ({
|
||||
key={`secret-reference-secret-${i + 1}`}
|
||||
>
|
||||
<div
|
||||
className={`${highlightedIndex === i ? "bg-gray-600" : ""
|
||||
} text-md relative mb-0.5 flex w-full cursor-pointer select-none items-center justify-between rounded-md px-2 py-1 outline-none transition-all hover:bg-mineshaft-500 data-[highlighted]:bg-mineshaft-500`}
|
||||
className={`${
|
||||
highlightedIndex === i ? "bg-gray-600" : ""
|
||||
} text-md relative mb-0.5 flex w-full cursor-pointer select-none items-center justify-between rounded-md px-2 py-1 outline-none transition-all hover:bg-mineshaft-500 data-[highlighted]:bg-mineshaft-500`}
|
||||
>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex items-center text-yellow-700">
|
||||
|
@ -3,5 +3,5 @@ import { IdentityAuthMethod } from "./enums";
|
||||
export const identityAuthToNameMap: { [I in IdentityAuthMethod]: string } = {
|
||||
[IdentityAuthMethod.UNIVERSAL_AUTH]: "Universal Auth",
|
||||
[IdentityAuthMethod.GCP_AUTH]: "GCP Auth",
|
||||
[IdentityAuthMethod.AWS_IAM_AUTH]: "AWS IAM Auth"
|
||||
[IdentityAuthMethod.AWS_AUTH]: "AWS Auth"
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
export enum IdentityAuthMethod {
|
||||
UNIVERSAL_AUTH = "universal-auth",
|
||||
GCP_AUTH = "gcp-auth",
|
||||
AWS_IAM_AUTH = "aws-iam-auth"
|
||||
AWS_AUTH = "aws-auth"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export { identityAuthToNameMap } from "./constants";
|
||||
export { IdentityAuthMethod } from "./enums";
|
||||
export {
|
||||
useAddIdentityAwsIamAuth,
|
||||
useAddIdentityAwsAuth,
|
||||
useAddIdentityGcpAuth,
|
||||
useAddIdentityUniversalAuth,
|
||||
useCreateIdentity,
|
||||
@ -9,12 +9,11 @@ export {
|
||||
useDeleteIdentity,
|
||||
useRevokeIdentityUniversalAuthClientSecret,
|
||||
useUpdateIdentity,
|
||||
useUpdateIdentityAwsIamAuth,
|
||||
useUpdateIdentityAwsAuth,
|
||||
useUpdateIdentityGcpAuth,
|
||||
useUpdateIdentityUniversalAuth
|
||||
} from "./mutations";
|
||||
useUpdateIdentityUniversalAuth} from "./mutations";
|
||||
export {
|
||||
useGetIdentityAwsIamAuth,
|
||||
useGetIdentityAwsAuth,
|
||||
useGetIdentityGcpAuth,
|
||||
useGetIdentityUniversalAuth,
|
||||
useGetIdentityUniversalAuthClientSecrets
|
||||
|
@ -5,7 +5,7 @@ import { apiRequest } from "@app/config/request";
|
||||
import { organizationKeys } from "../organization/queries";
|
||||
import { identitiesKeys } from "./queries";
|
||||
import {
|
||||
AddIdentityAwsIamAuthDTO,
|
||||
AddIdentityAwsAuthDTO,
|
||||
AddIdentityGcpAuthDTO,
|
||||
AddIdentityUniversalAuthDTO,
|
||||
ClientSecretData,
|
||||
@ -15,10 +15,10 @@ import {
|
||||
DeleteIdentityDTO,
|
||||
DeleteIdentityUniversalAuthClientSecretDTO,
|
||||
Identity,
|
||||
IdentityAwsIamAuth,
|
||||
IdentityAwsAuth,
|
||||
IdentityGcpAuth,
|
||||
IdentityUniversalAuth,
|
||||
UpdateIdentityAwsIamAuthDTO,
|
||||
UpdateIdentityAwsAuthDTO,
|
||||
UpdateIdentityDTO,
|
||||
UpdateIdentityGcpAuthDTO,
|
||||
UpdateIdentityUniversalAuthDTO
|
||||
@ -256,9 +256,9 @@ export const useUpdateIdentityGcpAuth = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAddIdentityAwsIamAuth = () => {
|
||||
export const useAddIdentityAwsAuth = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<IdentityAwsIamAuth, {}, AddIdentityAwsIamAuthDTO>({
|
||||
return useMutation<IdentityAwsAuth, {}, AddIdentityAwsAuthDTO>({
|
||||
mutationFn: async ({
|
||||
identityId,
|
||||
stsEndpoint,
|
||||
@ -270,9 +270,9 @@ export const useAddIdentityAwsIamAuth = () => {
|
||||
accessTokenTrustedIps
|
||||
}) => {
|
||||
const {
|
||||
data: { identityAwsIamAuth }
|
||||
} = await apiRequest.post<{ identityAwsIamAuth: IdentityAwsIamAuth }>(
|
||||
`/api/v1/auth/aws-iam-auth/identities/${identityId}`,
|
||||
data: { identityAwsAuth }
|
||||
} = await apiRequest.post<{ identityAwsAuth: IdentityAwsAuth }>(
|
||||
`/api/v1/auth/aws-auth/identities/${identityId}`,
|
||||
{
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
@ -284,7 +284,7 @@ export const useAddIdentityAwsIamAuth = () => {
|
||||
}
|
||||
);
|
||||
|
||||
return identityAwsIamAuth;
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||
@ -292,9 +292,9 @@ export const useAddIdentityAwsIamAuth = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateIdentityAwsIamAuth = () => {
|
||||
export const useUpdateIdentityAwsAuth = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<IdentityAwsIamAuth, {}, UpdateIdentityAwsIamAuthDTO>({
|
||||
return useMutation<IdentityAwsAuth, {}, UpdateIdentityAwsAuthDTO>({
|
||||
mutationFn: async ({
|
||||
identityId,
|
||||
stsEndpoint,
|
||||
@ -306,9 +306,9 @@ export const useUpdateIdentityAwsIamAuth = () => {
|
||||
accessTokenTrustedIps
|
||||
}) => {
|
||||
const {
|
||||
data: { identityAwsIamAuth }
|
||||
} = await apiRequest.patch<{ identityAwsIamAuth: IdentityAwsIamAuth }>(
|
||||
`/api/v1/auth/aws-iam-auth/identities/${identityId}`,
|
||||
data: { identityAwsAuth }
|
||||
} = await apiRequest.patch<{ identityAwsAuth: IdentityAwsAuth }>(
|
||||
`/api/v1/auth/aws-auth/identities/${identityId}`,
|
||||
{
|
||||
stsEndpoint,
|
||||
allowedPrincipalArns,
|
||||
@ -320,7 +320,7 @@ export const useUpdateIdentityAwsIamAuth = () => {
|
||||
}
|
||||
);
|
||||
|
||||
return identityAwsIamAuth;
|
||||
return identityAwsAuth;
|
||||
},
|
||||
onSuccess: (_, { organizationId }) => {
|
||||
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||
|
@ -2,12 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import {
|
||||
ClientSecretData,
|
||||
IdentityAwsIamAuth,
|
||||
IdentityGcpAuth,
|
||||
IdentityUniversalAuth
|
||||
} from "./types";
|
||||
import { ClientSecretData, IdentityAwsAuth, IdentityGcpAuth, IdentityUniversalAuth } from "./types";
|
||||
|
||||
export const identitiesKeys = {
|
||||
getIdentityUniversalAuth: (identityId: string) =>
|
||||
@ -15,7 +10,7 @@ export const identitiesKeys = {
|
||||
getIdentityUniversalAuthClientSecrets: (identityId: string) =>
|
||||
[{ identityId }, "identity-universal-auth-client-secrets"] as const,
|
||||
getIdentityGcpAuth: (identityId: string) => [{ identityId }, "identity-gcp-auth"] as const,
|
||||
getIdentityAwsIamAuth: (identityId: string) => [{ identityId }, "identity-aws-iam-auth"] as const
|
||||
getIdentityAwsAuth: (identityId: string) => [{ identityId }, "identity-aws-auth"] as const
|
||||
};
|
||||
|
||||
export const useGetIdentityUniversalAuth = (identityId: string) => {
|
||||
@ -63,17 +58,17 @@ export const useGetIdentityGcpAuth = (identityId: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetIdentityAwsIamAuth = (identityId: string) => {
|
||||
export const useGetIdentityAwsAuth = (identityId: string) => {
|
||||
return useQuery({
|
||||
enabled: Boolean(identityId),
|
||||
queryKey: identitiesKeys.getIdentityAwsIamAuth(identityId),
|
||||
queryKey: identitiesKeys.getIdentityAwsAuth(identityId),
|
||||
queryFn: async () => {
|
||||
const {
|
||||
data: { identityAwsIamAuth }
|
||||
} = await apiRequest.get<{ identityAwsIamAuth: IdentityAwsIamAuth }>(
|
||||
`/api/v1/auth/aws-iam-auth/identities/${identityId}`
|
||||
data: { identityAwsAuth }
|
||||
} = await apiRequest.get<{ identityAwsAuth: IdentityAwsAuth }>(
|
||||
`/api/v1/auth/aws-auth/identities/${identityId}`
|
||||
);
|
||||
return identityAwsIamAuth;
|
||||
return identityAwsAuth;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -158,8 +158,9 @@ export type UpdateIdentityGcpAuthDTO = {
|
||||
}[];
|
||||
};
|
||||
|
||||
export type IdentityAwsIamAuth = {
|
||||
export type IdentityAwsAuth = {
|
||||
identityId: string;
|
||||
type: "iam";
|
||||
stsEndpoint: string;
|
||||
allowedPrincipalArns: string;
|
||||
allowedAccountIds: string;
|
||||
@ -169,7 +170,7 @@ export type IdentityAwsIamAuth = {
|
||||
accessTokenTrustedIps: IdentityTrustedIp[];
|
||||
};
|
||||
|
||||
export type AddIdentityAwsIamAuthDTO = {
|
||||
export type AddIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
identityId: string;
|
||||
stsEndpoint: string;
|
||||
@ -183,7 +184,7 @@ export type AddIdentityAwsIamAuthDTO = {
|
||||
}[];
|
||||
};
|
||||
|
||||
export type UpdateIdentityAwsIamAuthDTO = {
|
||||
export type UpdateIdentityAwsAuthDTO = {
|
||||
organizationId: string;
|
||||
identityId: string;
|
||||
stsEndpoint?: string;
|
||||
|
@ -68,6 +68,7 @@ export const useCreateIntegration = () => {
|
||||
value: string;
|
||||
}[];
|
||||
kmsKeyId?: string;
|
||||
shouldDisableDelete?: boolean;
|
||||
};
|
||||
}) => {
|
||||
const {
|
||||
|
@ -79,7 +79,7 @@ export const useGetFoldersByEnv = ({
|
||||
});
|
||||
});
|
||||
return [...names];
|
||||
}, [(folders || []).map((folder) => folder.data)]);
|
||||
}, [...(folders || []).map((folder) => folder.data)]);
|
||||
|
||||
const isFolderPresentInEnv = useCallback(
|
||||
(name: string, env: string) => {
|
||||
@ -91,7 +91,7 @@ export const useGetFoldersByEnv = ({
|
||||
}
|
||||
return false;
|
||||
},
|
||||
[(folders || []).map((folder) => folder.data)]
|
||||
[...(folders || []).map((folder) => folder.data)]
|
||||
);
|
||||
|
||||
const getFolderByNameAndEnv = useCallback(
|
||||
|
@ -89,6 +89,7 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [shouldTag, setShouldTag] = useState(false);
|
||||
const [shouldDisableDelete, setShouldDisableDelete] = useState(false);
|
||||
const [tagKey, setTagKey] = useState("");
|
||||
const [tagValue, setTagValue] = useState("");
|
||||
const [kmsKeyId, setKmsKeyId] = useState("");
|
||||
@ -144,7 +145,8 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
]
|
||||
}
|
||||
: {}),
|
||||
...(kmsKeyId && { kmsKeyId })
|
||||
...(kmsKeyId && { kmsKeyId }),
|
||||
...(shouldDisableDelete && { shouldDisableDelete })
|
||||
}
|
||||
});
|
||||
|
||||
@ -273,6 +275,15 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
exit={{ opacity: 0, translateX: 30 }}
|
||||
>
|
||||
<div className="mt-2 ml-1">
|
||||
<Switch
|
||||
id="delete-aws"
|
||||
onCheckedChange={() => setShouldDisableDelete(!shouldDisableDelete)}
|
||||
isChecked={shouldDisableDelete}
|
||||
>
|
||||
Disable deleting secrets in AWS Parameter Store
|
||||
</Switch>
|
||||
</div>
|
||||
<div className="mt-4 ml-1">
|
||||
<Switch
|
||||
id="tag-aws"
|
||||
onCheckedChange={() => setShouldTag(!shouldTag)}
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
import { IdentityAwsIamAuthForm } from "./IdentityAwsIamAuthForm";
|
||||
import { IdentityAwsAuthForm } from "./IdentityAwsAuthForm";
|
||||
import { IdentityGcpAuthForm } from "./IdentityGcpAuthForm";
|
||||
import { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
||||
|
||||
@ -29,8 +29,8 @@ type Props = {
|
||||
|
||||
const identityAuthMethods = [
|
||||
{ label: "Universal Auth", value: IdentityAuthMethod.UNIVERSAL_AUTH },
|
||||
{ label: "AWS IAM Auth", value: IdentityAuthMethod.AWS_IAM_AUTH },
|
||||
{ label: "GCP Auth", value: IdentityAuthMethod.GCP_AUTH }
|
||||
{ label: "GCP Auth", value: IdentityAuthMethod.GCP_AUTH },
|
||||
{ label: "AWS Auth", value: IdentityAuthMethod.AWS_AUTH }
|
||||
];
|
||||
|
||||
const schema = yup
|
||||
@ -68,9 +68,9 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
|
||||
|
||||
const renderIdentityAuthForm = () => {
|
||||
switch (identityAuthMethodData?.authMethod ?? authMethod) {
|
||||
case IdentityAuthMethod.AWS_IAM_AUTH: {
|
||||
case IdentityAuthMethod.AWS_AUTH: {
|
||||
return (
|
||||
<IdentityAwsIamAuthForm
|
||||
<IdentityAwsAuthForm
|
||||
handlePopUpOpen={handlePopUpOpen}
|
||||
handlePopUpToggle={handlePopUpToggle}
|
||||
identityAuthMethodData={identityAuthMethodData}
|
||||
|
@ -9,9 +9,9 @@ import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FormControl, IconButton, Input } from "@app/components/v2";
|
||||
import { useOrganization, useSubscription } from "@app/context";
|
||||
import {
|
||||
useAddIdentityAwsIamAuth,
|
||||
useGetIdentityAwsIamAuth,
|
||||
useUpdateIdentityAwsIamAuth
|
||||
useAddIdentityAwsAuth,
|
||||
useGetIdentityAwsAuth,
|
||||
useUpdateIdentityAwsAuth
|
||||
} from "@app/hooks/api";
|
||||
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
||||
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
|
||||
@ -52,7 +52,7 @@ type Props = {
|
||||
};
|
||||
};
|
||||
|
||||
export const IdentityAwsIamAuthForm = ({
|
||||
export const IdentityAwsAuthForm = ({
|
||||
handlePopUpOpen,
|
||||
handlePopUpToggle,
|
||||
identityAuthMethodData
|
||||
@ -61,10 +61,10 @@ export const IdentityAwsIamAuthForm = ({
|
||||
const orgId = currentOrg?.id || "";
|
||||
const { subscription } = useSubscription();
|
||||
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAwsIamAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsIamAuth();
|
||||
const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth();
|
||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth();
|
||||
|
||||
const { data } = useGetIdentityAwsIamAuth(identityAuthMethodData?.identityId ?? "");
|
||||
const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? "");
|
||||
|
||||
const {
|
||||
control,
|
@ -13,7 +13,7 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: v0.5.0
|
||||
version: v0.5.1
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
|
@ -67,6 +67,8 @@ spec:
|
||||
properties:
|
||||
envSlug:
|
||||
type: string
|
||||
recursive:
|
||||
type: boolean
|
||||
secretsPath:
|
||||
type: string
|
||||
required:
|
||||
@ -111,6 +113,8 @@ spec:
|
||||
type: string
|
||||
projectSlug:
|
||||
type: string
|
||||
recursive:
|
||||
type: boolean
|
||||
secretsPath:
|
||||
type: string
|
||||
required:
|
||||
|
@ -32,7 +32,7 @@ controllerManager:
|
||||
- ALL
|
||||
image:
|
||||
repository: infisical/kubernetes-operator
|
||||
tag: v0.5.0 # fixed to prevent accidental upgrade
|
||||
tag: v0.5.1 # fixed to prevent accidental upgrade
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
|
@ -38,6 +38,8 @@ type SecretScopeInWorkspace struct {
|
||||
SecretsPath string `json:"secretsPath"`
|
||||
// +kubebuilder:validation:Required
|
||||
EnvSlug string `json:"envSlug"`
|
||||
// +kubebuilder:validation:Optional
|
||||
Recursive bool `json:"recursive"`
|
||||
}
|
||||
|
||||
type MachineIdentityScopeInWorkspace struct {
|
||||
@ -47,6 +49,8 @@ type MachineIdentityScopeInWorkspace struct {
|
||||
EnvSlug string `json:"envSlug"`
|
||||
// +kubebuilder:validation:Required
|
||||
ProjectSlug string `json:"projectSlug"`
|
||||
// +kubebuilder:validation:Optional
|
||||
Recursive bool `json:"recursive"`
|
||||
}
|
||||
|
||||
type KubeSecretReference struct {
|
||||
|
@ -67,6 +67,8 @@ spec:
|
||||
properties:
|
||||
envSlug:
|
||||
type: string
|
||||
recursive:
|
||||
type: boolean
|
||||
secretsPath:
|
||||
type: string
|
||||
required:
|
||||
@ -111,6 +113,8 @@ spec:
|
||||
type: string
|
||||
projectSlug:
|
||||
type: string
|
||||
recursive:
|
||||
type: boolean
|
||||
secretsPath:
|
||||
type: string
|
||||
required:
|
||||
|
@ -19,12 +19,14 @@ spec:
|
||||
secretsScope:
|
||||
envSlug: <env-slug>
|
||||
secretsPath: <secrets-path> # Root is "/"
|
||||
recursive: true # Wether or not to use recursive mode (Fetches all secrets in an environment from a given secret path, and all folders inside the path) / defaults to false
|
||||
|
||||
universalAuth:
|
||||
secretsScope:
|
||||
projectSlug: <project-slug>
|
||||
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
||||
secretsPath: "<secrets-path>" # Root is "/"
|
||||
recursive: true # Wether or not to use recursive mode (Fetches all secrets in an environment from a given secret path, and all folders inside the path) / defaults to false
|
||||
|
||||
credentialsRef:
|
||||
secretName: universal-auth-credentials
|
||||
|
@ -269,7 +269,7 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
||||
} else if infisicalMachineIdentityCreds.ClientId != "" && infisicalMachineIdentityCreds.ClientSecret != "" {
|
||||
authStrategy = AuthStrategy.UNIVERSAL_MACHINE_IDENTITY
|
||||
} else {
|
||||
return fmt.Errorf("no authentication method provided. You must provide either a valid service token or a service account details to fetch secrets")
|
||||
return fmt.Errorf("no authentication method provided. You must provide either a valid service token or a service account details to fetch secrets\n")
|
||||
}
|
||||
|
||||
r.SetInfisicalTokenLoadCondition(ctx, &infisicalSecret, err)
|
||||
@ -312,8 +312,9 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
||||
} else if authStrategy == AuthStrategy.SERVICE_TOKEN { // Service Tokens (deprecated)
|
||||
envSlug := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.EnvSlug
|
||||
secretsPath := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.SecretsPath
|
||||
recursive := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.Recursive
|
||||
|
||||
plainTextSecretsFromApi, updateDetails, err = util.GetPlainTextSecretsViaServiceToken(infisicalToken, secretVersionBasedOnETag, envSlug, secretsPath)
|
||||
plainTextSecretsFromApi, updateDetails, err = util.GetPlainTextSecretsViaServiceToken(infisicalToken, secretVersionBasedOnETag, envSlug, secretsPath, recursive)
|
||||
if err != nil {
|
||||
return fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
||||
}
|
||||
|
@ -66,6 +66,10 @@ func CallGetSecretsV3(httpClient *resty.Client, request GetEncryptedSecretsV3Req
|
||||
httpRequest.SetQueryParam("secretPath", request.SecretPath)
|
||||
}
|
||||
|
||||
if request.Recursive {
|
||||
httpRequest.SetQueryParam("recursive", "true")
|
||||
}
|
||||
|
||||
response, err := httpRequest.Get(fmt.Sprintf("%v/v3/secrets", API_HOST_URL))
|
||||
|
||||
if err != nil {
|
||||
@ -148,19 +152,23 @@ func CallUniversalMachineIdentityRefreshAccessToken(request MachineIdentityUnive
|
||||
func CallGetDecryptedSecretsV3(httpClient *resty.Client, request GetDecryptedSecretsV3Request) (GetDecryptedSecretsV3Response, error) {
|
||||
var decryptedSecretsResponse GetDecryptedSecretsV3Response
|
||||
|
||||
response, err := httpClient.
|
||||
req := httpClient.
|
||||
R().
|
||||
SetResult(&decryptedSecretsResponse).
|
||||
SetHeader("User-Agent", USER_AGENT_NAME).
|
||||
SetQueryParam("secretPath", request.SecretPath).
|
||||
SetQueryParam("workspaceSlug", request.ProjectSlug).
|
||||
SetQueryParam("environment", request.Environment).
|
||||
Get(fmt.Sprintf("%v/v3/secrets/raw", API_HOST_URL))
|
||||
SetQueryParam("environment", request.Environment)
|
||||
|
||||
if request.Recursive {
|
||||
req.SetQueryParam("recursive", "true")
|
||||
}
|
||||
|
||||
response, err := req.Get(fmt.Sprintf("%v/v3/secrets/raw", API_HOST_URL))
|
||||
|
||||
if err != nil {
|
||||
return GetDecryptedSecretsV3Response{}, fmt.Errorf("CallGetDecryptedSecretsV3: Unable to complete api request [err=%s]", err)
|
||||
}
|
||||
|
||||
if response.IsError() {
|
||||
return GetDecryptedSecretsV3Response{}, fmt.Errorf("CallGetDecryptedSecretsV3: Unsuccessful response: [response=%s]", response)
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ type GetEncryptedWorkspaceKeyResponse struct {
|
||||
type GetEncryptedSecretsV3Request struct {
|
||||
Environment string `json:"environment"`
|
||||
WorkspaceId string `json:"workspaceId"`
|
||||
Recursive bool `json:"recursive"`
|
||||
SecretPath string `json:"secretPath"`
|
||||
IncludeImport bool `json:"include_imports"`
|
||||
ETag string `json:"etag,omitempty"`
|
||||
@ -100,6 +101,7 @@ type GetDecryptedSecretsV3Request struct {
|
||||
ProjectSlug string `json:"workspaceSlug"`
|
||||
Environment string `json:"environment"`
|
||||
SecretPath string `json:"secretPath"`
|
||||
Recursive bool `json:"recursive"`
|
||||
ETag string `json:"etag,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,7 @@ func GetPlainTextSecretsViaUniversalAuth(accessToken string, etag string, secret
|
||||
secretsResponse, err := api.CallGetDecryptedSecretsV3(httpClient, api.GetDecryptedSecretsV3Request{
|
||||
ProjectSlug: secretScope.ProjectSlug,
|
||||
Environment: secretScope.EnvSlug,
|
||||
Recursive: secretScope.Recursive,
|
||||
SecretPath: secretScope.SecretsPath,
|
||||
ETag: etag,
|
||||
})
|
||||
@ -85,7 +86,7 @@ func GetPlainTextSecretsViaUniversalAuth(accessToken string, etag string, secret
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetPlainTextSecretsViaServiceToken(fullServiceToken string, etag string, envSlug string, secretPath string) ([]model.SingleEnvironmentVariable, model.RequestUpdateUpdateDetails, error) {
|
||||
func GetPlainTextSecretsViaServiceToken(fullServiceToken string, etag string, envSlug string, secretPath string, recursive bool) ([]model.SingleEnvironmentVariable, model.RequestUpdateUpdateDetails, error) {
|
||||
serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4)
|
||||
if len(serviceTokenParts) < 4 {
|
||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
||||
@ -106,6 +107,7 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string, etag string, en
|
||||
encryptedSecretsResponse, err := api.CallGetSecretsV3(httpClient, api.GetEncryptedSecretsV3Request{
|
||||
WorkspaceId: serviceTokenDetails.Workspace,
|
||||
Environment: envSlug,
|
||||
Recursive: recursive,
|
||||
ETag: etag,
|
||||
SecretPath: secretPath,
|
||||
})
|
||||
@ -376,7 +378,7 @@ func ExpandSecrets(secrets []model.SingleEnvironmentVariable, infisicalToken str
|
||||
|
||||
if crossRefSec, ok := crossEnvRefSecs[uniqKey]; !ok {
|
||||
// if not in cross reference cache, fetch it from server
|
||||
refSecs, _, err := GetPlainTextSecretsViaServiceToken(infisicalToken, "", env, secPath)
|
||||
refSecs, _, err := GetPlainTextSecretsViaServiceToken(infisicalToken, "", env, secPath, false)
|
||||
if err != nil {
|
||||
fmt.Printf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath)
|
||||
// HandleError(err, fmt.Sprintf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath), "If you are using a service token to fetch secrets, please ensure it is valid")
|
||||
|
1
pg-migrator/.gitignore
vendored
1
pg-migrator/.gitignore
vendored
@ -1 +0,0 @@
|
||||
db
|
1487
pg-migrator/package-lock.json
generated
1487
pg-migrator/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "pg-migrator",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"migration": "tsx src/index.ts",
|
||||
"rollback": "tsx src/rollback.ts",
|
||||
"migrate:audit-log": "tsx src/audit-log-migrator.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.11.0",
|
||||
"@types/prompt-sync": "^4.2.3",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"tsx": "^4.7.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@casl/ability": "^6.5.0",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"knex": "^3.1.0",
|
||||
"level": "^8.0.0",
|
||||
"mongoose": "^8.0.4",
|
||||
"nanoid": "^5.0.4",
|
||||
"pg": "^8.11.3",
|
||||
"prompt-sync": "^4.2.0",
|
||||
"uuid": "^9.0.1",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
451
pg-migrator/src/@types/knex.d.ts
vendored
451
pg-migrator/src/@types/knex.d.ts
vendored
@ -1,451 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import {
|
||||
TableName,
|
||||
TApiKeys,
|
||||
TApiKeysInsert,
|
||||
TApiKeysUpdate,
|
||||
TAuditLogs,
|
||||
TAuditLogsInsert,
|
||||
TAuditLogsUpdate,
|
||||
TAuthTokens,
|
||||
TAuthTokenSessions,
|
||||
TAuthTokenSessionsInsert,
|
||||
TAuthTokenSessionsUpdate,
|
||||
TAuthTokensInsert,
|
||||
TAuthTokensUpdate,
|
||||
TBackupPrivateKey,
|
||||
TBackupPrivateKeyInsert,
|
||||
TBackupPrivateKeyUpdate,
|
||||
TGitAppInstallSessions,
|
||||
TGitAppInstallSessionsInsert,
|
||||
TGitAppInstallSessionsUpdate,
|
||||
TGitAppOrg,
|
||||
TGitAppOrgInsert,
|
||||
TGitAppOrgUpdate,
|
||||
TIdentities,
|
||||
TIdentitiesInsert,
|
||||
TIdentitiesUpdate,
|
||||
TIdentityAccessTokens,
|
||||
TIdentityAccessTokensInsert,
|
||||
TIdentityAccessTokensUpdate,
|
||||
TIdentityOrgMemberships,
|
||||
TIdentityOrgMembershipsInsert,
|
||||
TIdentityOrgMembershipsUpdate,
|
||||
TIdentityProjectMemberships,
|
||||
TIdentityProjectMembershipsInsert,
|
||||
TIdentityProjectMembershipsUpdate,
|
||||
TIdentityUaClientSecrets,
|
||||
TIdentityUaClientSecretsInsert,
|
||||
TIdentityUaClientSecretsUpdate,
|
||||
TIdentityUniversalAuths,
|
||||
TIdentityUniversalAuthsInsert,
|
||||
TIdentityUniversalAuthsUpdate,
|
||||
TIncidentContacts,
|
||||
TIncidentContactsInsert,
|
||||
TIncidentContactsUpdate,
|
||||
TIntegrationAuths,
|
||||
TIntegrationAuthsInsert,
|
||||
TIntegrationAuthsUpdate,
|
||||
TIntegrations,
|
||||
TIntegrationsInsert,
|
||||
TIntegrationsUpdate,
|
||||
TOrganizations,
|
||||
TOrganizationsInsert,
|
||||
TOrganizationsUpdate,
|
||||
TOrgBots,
|
||||
TOrgBotsInsert,
|
||||
TOrgBotsUpdate,
|
||||
TOrgMemberships,
|
||||
TOrgMembershipsInsert,
|
||||
TOrgMembershipsUpdate,
|
||||
TOrgRoles,
|
||||
TOrgRolesInsert,
|
||||
TOrgRolesUpdate,
|
||||
TProjectBots,
|
||||
TProjectBotsInsert,
|
||||
TProjectBotsUpdate,
|
||||
TProjectEnvironments,
|
||||
TProjectEnvironmentsInsert,
|
||||
TProjectEnvironmentsUpdate,
|
||||
TProjectKeys,
|
||||
TProjectKeysInsert,
|
||||
TProjectKeysUpdate,
|
||||
TProjectMemberships,
|
||||
TProjectMembershipsInsert,
|
||||
TProjectMembershipsUpdate,
|
||||
TProjectRoles,
|
||||
TProjectRolesInsert,
|
||||
TProjectRolesUpdate,
|
||||
TProjects,
|
||||
TProjectsInsert,
|
||||
TProjectsUpdate,
|
||||
TSamlConfigs,
|
||||
TSamlConfigsInsert,
|
||||
TSamlConfigsUpdate,
|
||||
TSecretApprovalPolicies,
|
||||
TSecretApprovalPoliciesApprovers,
|
||||
TSecretApprovalPoliciesApproversInsert,
|
||||
TSecretApprovalPoliciesApproversUpdate,
|
||||
TSecretApprovalPoliciesInsert,
|
||||
TSecretApprovalPoliciesUpdate,
|
||||
TSecretApprovalRequests,
|
||||
TSecretApprovalRequestSecretTags,
|
||||
TSecretApprovalRequestSecretTagsInsert,
|
||||
TSecretApprovalRequestSecretTagsUpdate,
|
||||
TSecretApprovalRequestsInsert,
|
||||
TSecretApprovalRequestsReviewers,
|
||||
TSecretApprovalRequestsReviewersInsert,
|
||||
TSecretApprovalRequestsReviewersUpdate,
|
||||
TSecretApprovalRequestsSecrets,
|
||||
TSecretApprovalRequestsSecretsInsert,
|
||||
TSecretApprovalRequestsSecretsUpdate,
|
||||
TSecretApprovalRequestsUpdate,
|
||||
TSecretBlindIndexes,
|
||||
TSecretBlindIndexesInsert,
|
||||
TSecretBlindIndexesUpdate,
|
||||
TSecretFolders,
|
||||
TSecretFoldersInsert,
|
||||
TSecretFoldersUpdate,
|
||||
TSecretFolderVersions,
|
||||
TSecretFolderVersionsInsert,
|
||||
TSecretFolderVersionsUpdate,
|
||||
TSecretImports,
|
||||
TSecretImportsInsert,
|
||||
TSecretImportsUpdate,
|
||||
TSecretRotationOutputs,
|
||||
TSecretRotationOutputsInsert,
|
||||
TSecretRotationOutputsUpdate,
|
||||
TSecretRotations,
|
||||
TSecretRotationsInsert,
|
||||
TSecretRotationsUpdate,
|
||||
TSecrets,
|
||||
TSecretScanningGitRisks,
|
||||
TSecretScanningGitRisksInsert,
|
||||
TSecretScanningGitRisksUpdate,
|
||||
TSecretsInsert,
|
||||
TSecretSnapshotFolders,
|
||||
TSecretSnapshotFoldersInsert,
|
||||
TSecretSnapshotFoldersUpdate,
|
||||
TSecretSnapshots,
|
||||
TSecretSnapshotSecrets,
|
||||
TSecretSnapshotSecretsInsert,
|
||||
TSecretSnapshotSecretsUpdate,
|
||||
TSecretSnapshotsInsert,
|
||||
TSecretSnapshotsUpdate,
|
||||
TSecretsUpdate,
|
||||
TSecretTagJunction,
|
||||
TSecretTagJunctionInsert,
|
||||
TSecretTagJunctionUpdate,
|
||||
TSecretTags,
|
||||
TSecretTagsInsert,
|
||||
TSecretTagsUpdate,
|
||||
TSecretVersions,
|
||||
TSecretVersionsInsert,
|
||||
TSecretVersionsUpdate,
|
||||
TSecretVersionTagJunction,
|
||||
TSecretVersionTagJunctionInsert,
|
||||
TSecretVersionTagJunctionUpdate,
|
||||
TServiceTokens,
|
||||
TServiceTokensInsert,
|
||||
TServiceTokensUpdate,
|
||||
TSuperAdmin,
|
||||
TSuperAdminInsert,
|
||||
TSuperAdminUpdate,
|
||||
TTrustedIps,
|
||||
TTrustedIpsInsert,
|
||||
TTrustedIpsUpdate,
|
||||
TUserActions,
|
||||
TUserActionsInsert,
|
||||
TUserActionsUpdate,
|
||||
TUserEncryptionKeys,
|
||||
TUserEncryptionKeysInsert,
|
||||
TUserEncryptionKeysUpdate,
|
||||
TUsers,
|
||||
TUsersInsert,
|
||||
TUsersUpdate,
|
||||
TWebhooks,
|
||||
TWebhooksInsert,
|
||||
TWebhooksUpdate,
|
||||
} from "../schemas";
|
||||
|
||||
declare module "knex/types/tables" {
|
||||
interface Tables {
|
||||
[TableName.Users]: Knex.CompositeTableType<
|
||||
TUsers,
|
||||
TUsersInsert,
|
||||
TUsersUpdate
|
||||
>;
|
||||
[TableName.UserEncryptionKey]: Knex.CompositeTableType<
|
||||
TUserEncryptionKeys,
|
||||
TUserEncryptionKeysInsert,
|
||||
TUserEncryptionKeysUpdate
|
||||
>;
|
||||
[TableName.AuthTokens]: Knex.CompositeTableType<
|
||||
TAuthTokens,
|
||||
TAuthTokensInsert,
|
||||
TAuthTokensUpdate
|
||||
>;
|
||||
[TableName.AuthTokenSession]: Knex.CompositeTableType<
|
||||
TAuthTokenSessions,
|
||||
TAuthTokenSessionsInsert,
|
||||
TAuthTokenSessionsUpdate
|
||||
>;
|
||||
[TableName.BackupPrivateKey]: Knex.CompositeTableType<
|
||||
TBackupPrivateKey,
|
||||
TBackupPrivateKeyInsert,
|
||||
TBackupPrivateKeyUpdate
|
||||
>;
|
||||
[TableName.Organization]: Knex.CompositeTableType<
|
||||
TOrganizations,
|
||||
TOrganizationsInsert,
|
||||
TOrganizationsUpdate
|
||||
>;
|
||||
[TableName.OrgMembership]: Knex.CompositeTableType<
|
||||
TOrgMemberships,
|
||||
TOrgMembershipsInsert,
|
||||
TOrgMembershipsUpdate
|
||||
>;
|
||||
[TableName.OrgRoles]: Knex.CompositeTableType<
|
||||
TOrgRoles,
|
||||
TOrgRolesInsert,
|
||||
TOrgRolesUpdate
|
||||
>;
|
||||
[TableName.IncidentContact]: Knex.CompositeTableType<
|
||||
TIncidentContacts,
|
||||
TIncidentContactsInsert,
|
||||
TIncidentContactsUpdate
|
||||
>;
|
||||
[TableName.UserAction]: Knex.CompositeTableType<
|
||||
TUserActions,
|
||||
TUserActionsInsert,
|
||||
TUserActionsUpdate
|
||||
>;
|
||||
[TableName.SuperAdmin]: Knex.CompositeTableType<
|
||||
TSuperAdmin,
|
||||
TSuperAdminInsert,
|
||||
TSuperAdminUpdate
|
||||
>;
|
||||
[TableName.ApiKey]: Knex.CompositeTableType<
|
||||
TApiKeys,
|
||||
TApiKeysInsert,
|
||||
TApiKeysUpdate
|
||||
>;
|
||||
[TableName.Project]: Knex.CompositeTableType<
|
||||
TProjects,
|
||||
TProjectsInsert,
|
||||
TProjectsUpdate
|
||||
>;
|
||||
[TableName.ProjectMembership]: Knex.CompositeTableType<
|
||||
TProjectMemberships,
|
||||
TProjectMembershipsInsert,
|
||||
TProjectMembershipsUpdate
|
||||
>;
|
||||
[TableName.Environment]: Knex.CompositeTableType<
|
||||
TProjectEnvironments,
|
||||
TProjectEnvironmentsInsert,
|
||||
TProjectEnvironmentsUpdate
|
||||
>;
|
||||
[TableName.ProjectBot]: Knex.CompositeTableType<
|
||||
TProjectBots,
|
||||
TProjectBotsInsert,
|
||||
TProjectBotsUpdate
|
||||
>;
|
||||
[TableName.ProjectRoles]: Knex.CompositeTableType<
|
||||
TProjectRoles,
|
||||
TProjectRolesInsert,
|
||||
TProjectRolesUpdate
|
||||
>;
|
||||
[TableName.ProjectKeys]: Knex.CompositeTableType<
|
||||
TProjectKeys,
|
||||
TProjectKeysInsert,
|
||||
TProjectKeysUpdate
|
||||
>;
|
||||
[TableName.Secret]: Knex.CompositeTableType<
|
||||
TSecrets,
|
||||
TSecretsInsert,
|
||||
TSecretsUpdate
|
||||
>;
|
||||
[TableName.SecretBlindIndex]: Knex.CompositeTableType<
|
||||
TSecretBlindIndexes,
|
||||
TSecretBlindIndexesInsert,
|
||||
TSecretBlindIndexesUpdate
|
||||
>;
|
||||
[TableName.SecretVersion]: Knex.CompositeTableType<
|
||||
TSecretVersions,
|
||||
TSecretVersionsInsert,
|
||||
TSecretVersionsUpdate
|
||||
>;
|
||||
[TableName.SecretFolder]: Knex.CompositeTableType<
|
||||
TSecretFolders,
|
||||
TSecretFoldersInsert,
|
||||
TSecretFoldersUpdate
|
||||
>;
|
||||
[TableName.SecretFolderVersion]: Knex.CompositeTableType<
|
||||
TSecretFolderVersions,
|
||||
TSecretFolderVersionsInsert,
|
||||
TSecretFolderVersionsUpdate
|
||||
>;
|
||||
[TableName.SecretTag]: Knex.CompositeTableType<
|
||||
TSecretTags,
|
||||
TSecretTagsInsert,
|
||||
TSecretTagsUpdate
|
||||
>;
|
||||
[TableName.SecretImport]: Knex.CompositeTableType<
|
||||
TSecretImports,
|
||||
TSecretImportsInsert,
|
||||
TSecretImportsUpdate
|
||||
>;
|
||||
[TableName.Integration]: Knex.CompositeTableType<
|
||||
TIntegrations,
|
||||
TIntegrationsInsert,
|
||||
TIntegrationsUpdate
|
||||
>;
|
||||
[TableName.Webhook]: Knex.CompositeTableType<
|
||||
TWebhooks,
|
||||
TWebhooksInsert,
|
||||
TWebhooksUpdate
|
||||
>;
|
||||
[TableName.ServiceToken]: Knex.CompositeTableType<
|
||||
TServiceTokens,
|
||||
TServiceTokensInsert,
|
||||
TServiceTokensUpdate
|
||||
>;
|
||||
[TableName.IntegrationAuth]: Knex.CompositeTableType<
|
||||
TIntegrationAuths,
|
||||
TIntegrationAuthsInsert,
|
||||
TIntegrationAuthsUpdate
|
||||
>;
|
||||
[TableName.Identity]: Knex.CompositeTableType<
|
||||
TIdentities,
|
||||
TIdentitiesInsert,
|
||||
TIdentitiesUpdate
|
||||
>;
|
||||
[TableName.IdentityUniversalAuth]: Knex.CompositeTableType<
|
||||
TIdentityUniversalAuths,
|
||||
TIdentityUniversalAuthsInsert,
|
||||
TIdentityUniversalAuthsUpdate
|
||||
>;
|
||||
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
||||
TIdentityUaClientSecrets,
|
||||
TIdentityUaClientSecretsInsert,
|
||||
TIdentityUaClientSecretsUpdate
|
||||
>;
|
||||
[TableName.IdentityAccessToken]: Knex.CompositeTableType<
|
||||
TIdentityAccessTokens,
|
||||
TIdentityAccessTokensInsert,
|
||||
TIdentityAccessTokensUpdate
|
||||
>;
|
||||
[TableName.IdentityOrgMembership]: Knex.CompositeTableType<
|
||||
TIdentityOrgMemberships,
|
||||
TIdentityOrgMembershipsInsert,
|
||||
TIdentityOrgMembershipsUpdate
|
||||
>;
|
||||
[TableName.IdentityProjectMembership]: Knex.CompositeTableType<
|
||||
TIdentityProjectMemberships,
|
||||
TIdentityProjectMembershipsInsert,
|
||||
TIdentityProjectMembershipsUpdate
|
||||
>;
|
||||
[TableName.SecretApprovalPolicy]: Knex.CompositeTableType<
|
||||
TSecretApprovalPolicies,
|
||||
TSecretApprovalPoliciesInsert,
|
||||
TSecretApprovalPoliciesUpdate
|
||||
>;
|
||||
[TableName.SecretApprovalPolicyApprover]: Knex.CompositeTableType<
|
||||
TSecretApprovalPoliciesApprovers,
|
||||
TSecretApprovalPoliciesApproversInsert,
|
||||
TSecretApprovalPoliciesApproversUpdate
|
||||
>;
|
||||
[TableName.SecretApprovalRequest]: Knex.CompositeTableType<
|
||||
TSecretApprovalRequests,
|
||||
TSecretApprovalRequestsInsert,
|
||||
TSecretApprovalRequestsUpdate
|
||||
>;
|
||||
[TableName.SecretApprovalRequestReviewer]: Knex.CompositeTableType<
|
||||
TSecretApprovalRequestsReviewers,
|
||||
TSecretApprovalRequestsReviewersInsert,
|
||||
TSecretApprovalRequestsReviewersUpdate
|
||||
>;
|
||||
[TableName.SecretApprovalRequestSecret]: Knex.CompositeTableType<
|
||||
TSecretApprovalRequestsSecrets,
|
||||
TSecretApprovalRequestsSecretsInsert,
|
||||
TSecretApprovalRequestsSecretsUpdate
|
||||
>;
|
||||
[TableName.SecretApprovalRequestSecretTag]: Knex.CompositeTableType<
|
||||
TSecretApprovalRequestSecretTags,
|
||||
TSecretApprovalRequestSecretTagsInsert,
|
||||
TSecretApprovalRequestSecretTagsUpdate
|
||||
>;
|
||||
[TableName.SecretRotation]: Knex.CompositeTableType<
|
||||
TSecretRotations,
|
||||
TSecretRotationsInsert,
|
||||
TSecretRotationsUpdate
|
||||
>;
|
||||
[TableName.SecretRotationOutput]: Knex.CompositeTableType<
|
||||
TSecretRotationOutputs,
|
||||
TSecretRotationOutputsInsert,
|
||||
TSecretRotationOutputsUpdate
|
||||
>;
|
||||
[TableName.Snapshot]: Knex.CompositeTableType<
|
||||
TSecretSnapshots,
|
||||
TSecretSnapshotsInsert,
|
||||
TSecretSnapshotsUpdate
|
||||
>;
|
||||
[TableName.SnapshotSecret]: Knex.CompositeTableType<
|
||||
TSecretSnapshotSecrets,
|
||||
TSecretSnapshotSecretsInsert,
|
||||
TSecretSnapshotSecretsUpdate
|
||||
>;
|
||||
[TableName.SnapshotFolder]: Knex.CompositeTableType<
|
||||
TSecretSnapshotFolders,
|
||||
TSecretSnapshotFoldersInsert,
|
||||
TSecretSnapshotFoldersUpdate
|
||||
>;
|
||||
[TableName.SamlConfig]: Knex.CompositeTableType<
|
||||
TSamlConfigs,
|
||||
TSamlConfigsInsert,
|
||||
TSamlConfigsUpdate
|
||||
>;
|
||||
[TableName.OrgBot]: Knex.CompositeTableType<
|
||||
TOrgBots,
|
||||
TOrgBotsInsert,
|
||||
TOrgBotsUpdate
|
||||
>;
|
||||
[TableName.AuditLog]: Knex.CompositeTableType<
|
||||
TAuditLogs,
|
||||
TAuditLogsInsert,
|
||||
TAuditLogsUpdate
|
||||
>;
|
||||
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
||||
TGitAppInstallSessions,
|
||||
TGitAppInstallSessionsInsert,
|
||||
TGitAppInstallSessionsUpdate
|
||||
>;
|
||||
[TableName.GitAppOrg]: Knex.CompositeTableType<
|
||||
TGitAppOrg,
|
||||
TGitAppOrgInsert,
|
||||
TGitAppOrgUpdate
|
||||
>;
|
||||
[TableName.SecretScanningGitRisk]: Knex.CompositeTableType<
|
||||
TSecretScanningGitRisks,
|
||||
TSecretScanningGitRisksInsert,
|
||||
TSecretScanningGitRisksUpdate
|
||||
>;
|
||||
[TableName.TrustedIps]: Knex.CompositeTableType<
|
||||
TTrustedIps,
|
||||
TTrustedIpsInsert,
|
||||
TTrustedIpsUpdate
|
||||
>;
|
||||
// Junction tables
|
||||
[TableName.JnSecretTag]: Knex.CompositeTableType<
|
||||
TSecretTagJunction,
|
||||
TSecretTagJunctionInsert,
|
||||
TSecretTagJunctionUpdate
|
||||
>;
|
||||
[TableName.SecretVersionTag]: Knex.CompositeTableType<
|
||||
TSecretVersionTagJunction,
|
||||
TSecretVersionTagJunctionInsert,
|
||||
TSecretVersionTagJunctionUpdate
|
||||
>;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
||||
import { TFolderSchema } from "./models";
|
||||
|
||||
export const folderBfsTraversal = async (
|
||||
root: TFolderSchema,
|
||||
callback: (
|
||||
data: TFolderSchema & { parentId: string | null },
|
||||
) => void | Promise<void>,
|
||||
) => {
|
||||
const queue = [root];
|
||||
while (queue.length) {
|
||||
const folder = queue.pop() as TFolderSchema & { parentId: null };
|
||||
callback(folder);
|
||||
queue.push(
|
||||
...folder.children.map((el) => ({
|
||||
...el,
|
||||
parentId: folder.id,
|
||||
})),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const flattenFolders = (folders: TFolderSchema) => {
|
||||
const flattened: {
|
||||
id: string;
|
||||
parentId: string | null;
|
||||
name: string;
|
||||
version: number;
|
||||
}[] = [];
|
||||
|
||||
if(!folders) return []
|
||||
|
||||
folderBfsTraversal(folders, ({ name, version, parentId, id }) => {
|
||||
flattened.push({ name, version, parentId, id });
|
||||
});
|
||||
return flattened;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import {
|
||||
createOnUpdateTrigger,
|
||||
createUpdateAtTriggerFunction,
|
||||
dropOnUpdateTrigger,
|
||||
dropUpdatedAtTriggerFunction
|
||||
} from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.Users);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.Users, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("email").notNullable();
|
||||
t.specificType("authMethods", "text[]");
|
||||
t.boolean("superAdmin").defaultTo(false);
|
||||
t.string("firstName");
|
||||
t.string("lastName");
|
||||
t.boolean("isAccepted").defaultTo(false);
|
||||
t.boolean("isMfaEnabled").defaultTo(false);
|
||||
t.specificType("mfaMethods", "text[]");
|
||||
t.jsonb("devices");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createUpdateAtTriggerFunction(knex);
|
||||
await createOnUpdateTrigger(knex, TableName.Users);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.Users);
|
||||
await dropOnUpdateTrigger(knex, TableName.Users);
|
||||
await dropUpdatedAtTriggerFunction(knex);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.UserEncryptionKey);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.UserEncryptionKey, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.text("clientPublicKey");
|
||||
t.text("serverPrivateKey");
|
||||
t.integer("encryptionVersion").defaultTo(2);
|
||||
t.text("protectedKey");
|
||||
t.text("protectedKeyIV");
|
||||
t.text("protectedKeyTag");
|
||||
t.text("publicKey").notNullable();
|
||||
t.text("encryptedPrivateKey").notNullable();
|
||||
t.text("iv").notNullable();
|
||||
t.text("tag").notNullable();
|
||||
t.text("salt").notNullable();
|
||||
t.text("verifier").notNullable();
|
||||
// one to one relationship
|
||||
t.uuid("userId").notNullable().unique();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.UserEncryptionKey);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.AuthTokens);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.AuthTokens, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("type").notNullable();
|
||||
t.string("phoneNumber");
|
||||
t.string("tokenHash").notNullable();
|
||||
t.integer("triesLeft");
|
||||
t.datetime("expiresAt").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId");
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.AuthTokens);
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.AuthTokenSession);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.AuthTokenSession, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("ip").notNullable();
|
||||
t.string("userAgent");
|
||||
t.integer("refreshVersion").notNullable().defaultTo(1);
|
||||
t.integer("accessVersion").notNullable().defaultTo(1);
|
||||
t.datetime("lastUsed").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId").notNullable();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.AuthTokenSession);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.AuthTokenSession);
|
||||
await dropOnUpdateTrigger(knex, TableName.AuthTokenSession);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const doesTableExist = await knex.schema.hasTable(TableName.BackupPrivateKey);
|
||||
if (!doesTableExist) {
|
||||
await knex.schema.createTable(TableName.BackupPrivateKey, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.text("encryptedPrivateKey").notNullable();
|
||||
t.text("iv").notNullable();
|
||||
t.text("tag").notNullable();
|
||||
t.string("algorithm").notNullable();
|
||||
t.string("keyEncoding").notNullable();
|
||||
t.text("salt").notNullable();
|
||||
t.text("verifier").notNullable();
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId").notNullable().unique();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.BackupPrivateKey);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.Organization);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.Organization, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("customerId");
|
||||
t.string("slug").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.unique("slug");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
|
||||
t.uuid("orgId");
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.Organization);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
if (await knex.schema.hasColumn(TableName.AuthTokens, "orgId")) {
|
||||
await knex.schema.alterTable(TableName.AuthTokens, (t) => {
|
||||
t.dropColumn("orgId");
|
||||
});
|
||||
}
|
||||
await knex.schema.dropTableIfExists(TableName.Organization);
|
||||
await dropOnUpdateTrigger(knex, TableName.Organization);
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { OrgMembershipStatus } from "../schemas/models";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isOrgRolePresent = await knex.schema.hasTable(TableName.OrgRoles);
|
||||
if (!isOrgRolePresent) {
|
||||
await knex.schema.createTable(TableName.OrgRoles, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("description");
|
||||
t.string("slug").notNullable();
|
||||
t.jsonb("permissions").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
|
||||
const isOrgTablePresent = await knex.schema.hasTable(TableName.OrgMembership);
|
||||
if (!isOrgTablePresent) {
|
||||
await knex.schema.createTable(TableName.OrgMembership, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("role").notNullable();
|
||||
t.string("status").notNullable().defaultTo(OrgMembershipStatus.Invited);
|
||||
t.string("inviteEmail");
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId");
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.uuid("roleId");
|
||||
t.foreign("roleId").references("id").inTable(TableName.OrgRoles);
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.OrgMembership);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.OrgMembership);
|
||||
await knex.schema.dropTableIfExists(TableName.OrgRoles);
|
||||
await dropOnUpdateTrigger(knex, TableName.OrgMembership);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.IncidentContact);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.IncidentContact, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("email").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.IncidentContact);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.IncidentContact);
|
||||
await dropOnUpdateTrigger(knex, TableName.IncidentContact);
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.UserAction);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.UserAction, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("action").notNullable();
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId").notNullable();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.UserAction);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.SuperAdmin);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.SuperAdmin, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.boolean("initialized").defaultTo(false);
|
||||
t.boolean("allowSignUp").defaultTo(true);
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
// this is a one time function
|
||||
await createOnUpdateTrigger(knex, TableName.SuperAdmin);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SuperAdmin);
|
||||
await dropOnUpdateTrigger(knex, TableName.SuperAdmin);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
const isTablePresent = await knex.schema.hasTable(TableName.ApiKey);
|
||||
if (!isTablePresent) {
|
||||
await knex.schema.createTable(TableName.ApiKey, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.datetime("lastUsed");
|
||||
t.datetime("expiresAt");
|
||||
t.string("secretHash").notNullable();
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId").notNullable();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.ApiKey);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.ApiKey);
|
||||
await dropOnUpdateTrigger(knex, TableName.ApiKey);
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.Project))) {
|
||||
await knex.schema.createTable(TableName.Project, (t) => {
|
||||
t.string("id", 36).primary().defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("slug").notNullable();
|
||||
t.boolean("autoCapitalization").defaultTo(true);
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
t.unique(["orgId", "slug"]);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.Project);
|
||||
// environments
|
||||
if (!(await knex.schema.hasTable(TableName.Environment))) {
|
||||
await knex.schema.createTable(TableName.Environment, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("slug").notNullable();
|
||||
t.integer("position").notNullable();
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
// this will ensure ever env has its position
|
||||
t.unique(["projectId", "position"], {
|
||||
indexName: "env_pos_composite_uniqe",
|
||||
deferrable: "deferred"
|
||||
});
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
// project key
|
||||
if (!(await knex.schema.hasTable(TableName.ProjectKeys))) {
|
||||
await knex.schema.createTable(TableName.ProjectKeys, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.text("encryptedKey").notNullable();
|
||||
t.text("nonce").notNullable();
|
||||
t.uuid("receiverId").notNullable();
|
||||
t.foreign("receiverId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
t.uuid("senderId");
|
||||
// if sender is deleted just don't do anything to this record
|
||||
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.ProjectKeys);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.Environment);
|
||||
await knex.schema.dropTableIfExists(TableName.ProjectKeys);
|
||||
await knex.schema.dropTableIfExists(TableName.Project);
|
||||
await dropOnUpdateTrigger(knex, TableName.ProjectKeys);
|
||||
await dropOnUpdateTrigger(knex, TableName.Project);
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.ProjectRoles))) {
|
||||
await knex.schema.createTable(TableName.ProjectRoles, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("description");
|
||||
t.string("slug").notNullable();
|
||||
t.jsonb("permissions").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.ProjectMembership))) {
|
||||
await knex.schema.createTable(TableName.ProjectMembership, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("role").notNullable();
|
||||
// does not need update trigger we will do it manually
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("userId").notNullable();
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
// until role is changed/removed the role should not deleted
|
||||
t.uuid("roleId");
|
||||
t.foreign("roleId").references("id").inTable(TableName.ProjectRoles);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.ProjectMembership);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.ProjectMembership);
|
||||
await knex.schema.dropTableIfExists(TableName.ProjectRoles);
|
||||
await dropOnUpdateTrigger(knex, TableName.ProjectMembership);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretFolder))) {
|
||||
await knex.schema.createTable(TableName.SecretFolder, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.integer("version").defaultTo(1);
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.uuid("parentId");
|
||||
t.foreign("parentId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretFolder);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretFolderVersion))) {
|
||||
await knex.schema.createTable(TableName.SecretFolderVersion, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.integer("version").defaultTo(1);
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.uuid("folderId").notNullable();
|
||||
// t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("SET NULL");
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.SecretFolderVersion);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretFolderVersion);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretFolder);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretFolder);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretFolderVersion);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretImport))) {
|
||||
await knex.schema.createTable(TableName.SecretImport, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.integer("version").defaultTo(1);
|
||||
t.string("importPath").notNullable();
|
||||
t.uuid("importEnv").notNullable();
|
||||
t.foreign("importEnv").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.integer("position").notNullable();
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("folderId").notNullable();
|
||||
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||
t.unique(["folderId", "position"], {
|
||||
indexName: "import_pos_composite_uniqe",
|
||||
deferrable: "deferred"
|
||||
});
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretImport);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretImport);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretImport);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretTag))) {
|
||||
await knex.schema.createTable(TableName.SecretTag, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("slug").notNullable();
|
||||
t.string("color");
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("createdBy");
|
||||
t.foreign("createdBy").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretTag);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretTag);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretTag);
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import {
|
||||
SecretEncryptionAlgo,
|
||||
SecretKeyEncoding,
|
||||
SecretType,
|
||||
TableName,
|
||||
} from "../schemas";
|
||||
import {
|
||||
createJunctionTable,
|
||||
createOnUpdateTrigger,
|
||||
dropOnUpdateTrigger,
|
||||
} from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretBlindIndex))) {
|
||||
await knex.schema.createTable(TableName.SecretBlindIndex, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.text("encryptedSaltCipherText").notNullable();
|
||||
t.text("saltIV").notNullable();
|
||||
t.text("saltTag").notNullable();
|
||||
t.string("algorithm")
|
||||
.notNullable()
|
||||
.defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||
t.string("projectId").notNullable().unique();
|
||||
t.foreign("projectId")
|
||||
.references("id")
|
||||
.inTable(TableName.Project)
|
||||
.onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretBlindIndex);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.Secret))) {
|
||||
await knex.schema.createTable(TableName.Secret, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.integer("version").defaultTo(1).notNullable();
|
||||
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
||||
// t.text("secretKeyHash").notNullable();
|
||||
// t.text("secretValueHash");
|
||||
// t.text("secretCommentHash");
|
||||
// this is required but for backward compatiability we are making it nullable
|
||||
t.text("secretBlindIndex");
|
||||
t.text("secretKeyCiphertext").notNullable();
|
||||
t.text("secretKeyIV").notNullable();
|
||||
t.text("secretKeyTag").notNullable();
|
||||
t.text("secretValueCiphertext").notNullable();
|
||||
t.text("secretValueIV").notNullable(); // symmetric encryption
|
||||
t.text("secretValueTag").notNullable();
|
||||
t.text("secretCommentCiphertext");
|
||||
t.text("secretCommentIV");
|
||||
t.text("secretCommentTag");
|
||||
t.string("secretReminderNote");
|
||||
t.integer("secretReminderRepeatDays");
|
||||
t.boolean("skipMultilineEncoding").defaultTo(false);
|
||||
t.string("algorithm")
|
||||
.notNullable()
|
||||
.defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||
t.jsonb("metadata");
|
||||
t.uuid("userId");
|
||||
t.foreign("userId")
|
||||
.references("id")
|
||||
.inTable(TableName.Users)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("folderId").notNullable();
|
||||
t.foreign("folderId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretFolder)
|
||||
.onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.Secret);
|
||||
// many to many relation between tags
|
||||
await createJunctionTable(
|
||||
knex,
|
||||
TableName.JnSecretTag,
|
||||
TableName.Secret,
|
||||
TableName.SecretTag,
|
||||
);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretBlindIndex);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretBlindIndex);
|
||||
|
||||
await knex.schema.dropTableIfExists(TableName.JnSecretTag);
|
||||
await knex.schema.dropTableIfExists(TableName.Secret);
|
||||
await dropOnUpdateTrigger(knex, TableName.Secret);
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { SecretEncryptionAlgo, SecretKeyEncoding, SecretType, TableName } from "../schemas";
|
||||
import { createJunctionTable, createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretVersion))) {
|
||||
await knex.schema.createTable(TableName.SecretVersion, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.integer("version").defaultTo(1).notNullable();
|
||||
t.string("type").notNullable().defaultTo(SecretType.Shared);
|
||||
t.text("secretBlindIndex");
|
||||
t.text("secretKeyCiphertext").notNullable();
|
||||
t.text("secretKeyIV").notNullable();
|
||||
t.text("secretKeyTag").notNullable();
|
||||
t.text("secretValueCiphertext").notNullable();
|
||||
t.text("secretValueIV").notNullable(); // symmetric encryption
|
||||
t.text("secretValueTag").notNullable();
|
||||
t.text("secretCommentCiphertext");
|
||||
t.text("secretCommentIV");
|
||||
t.text("secretCommentTag");
|
||||
t.string("secretReminderNote");
|
||||
t.integer("secretReminderRepeatDays");
|
||||
t.boolean("skipMultilineEncoding").defaultTo(false);
|
||||
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||
t.jsonb("metadata");
|
||||
// to avoid orphan rows
|
||||
t.uuid("envId");
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.uuid("secretId").notNullable();
|
||||
t.uuid("folderId").notNullable();
|
||||
// t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL");
|
||||
t.uuid("userId");
|
||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretVersion);
|
||||
// many to many relation between tags
|
||||
await createJunctionTable(
|
||||
knex,
|
||||
TableName.SecretVersionTag,
|
||||
TableName.SecretVersion,
|
||||
TableName.SecretTag
|
||||
);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretVersionTag);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretVersion);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretVersion);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.ProjectBot))) {
|
||||
await knex.schema.createTable(TableName.ProjectBot, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.boolean("isActive").defaultTo(false).notNullable();
|
||||
t.text("encryptedPrivateKey").notNullable();
|
||||
t.text("publicKey").notNullable();
|
||||
t.text("iv").notNullable();
|
||||
t.text("tag").notNullable();
|
||||
t.string("algorithm").notNullable();
|
||||
t.string("keyEncoding").notNullable();
|
||||
t.text("encryptedProjectKey");
|
||||
t.text("encryptedProjectKeyNonce");
|
||||
// one to one relationship
|
||||
t.string("projectId").notNullable().unique();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
t.uuid("senderId");
|
||||
t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.ProjectBot);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.ProjectBot);
|
||||
await dropOnUpdateTrigger(knex, TableName.ProjectBot);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.IntegrationAuth))) {
|
||||
await knex.schema.createTable(TableName.IntegrationAuth, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("integration").notNullable();
|
||||
t.string("teamId"); // vercel-specific
|
||||
t.string("url"); // for self hosted
|
||||
t.string("namespace"); // hashicorp specific
|
||||
t.string("accountId"); // netlify
|
||||
t.text("refreshCiphertext");
|
||||
t.string("refreshIV");
|
||||
t.string("refreshTag");
|
||||
t.string("accessIdCiphertext");
|
||||
t.string("accessIdIV");
|
||||
t.string("accessIdTag");
|
||||
t.text("accessCiphertext");
|
||||
t.string("accessIV");
|
||||
t.string("accessTag");
|
||||
t.datetime("accessExpiresAt");
|
||||
t.jsonb("metadata");
|
||||
t.string("algorithm").notNullable();
|
||||
t.string("keyEncoding").notNullable();
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.IntegrationAuth);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.Integration))) {
|
||||
await knex.schema.createTable(TableName.Integration, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.boolean("isActive").notNullable();
|
||||
t.string("url"); // self hosted
|
||||
t.string("app"); // name of app in provider
|
||||
t.string("appId");
|
||||
t.string("targetEnvironment");
|
||||
t.string("targetEnvironmentId");
|
||||
t.string("targetService"); // railway - qovery specific
|
||||
t.string("targetServiceId");
|
||||
t.string("owner"); // github specific
|
||||
t.string("path"); // aws parameter store / vercel preview branch
|
||||
t.string("region"); // aws
|
||||
t.string("scope"); // qovery specific scope
|
||||
t.string("integration").notNullable();
|
||||
t.jsonb("metadata");
|
||||
t.uuid("integrationAuthId").notNullable();
|
||||
t.foreign("integrationAuthId")
|
||||
.references("id")
|
||||
.inTable(TableName.IntegrationAuth)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("envId").notNullable();
|
||||
t.string("secretPath").defaultTo("/").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.Integration);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.Integration);
|
||||
await knex.schema.dropTableIfExists(TableName.IntegrationAuth);
|
||||
await dropOnUpdateTrigger(knex, TableName.IntegrationAuth);
|
||||
await dropOnUpdateTrigger(knex, TableName.Integration);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.ServiceToken))) {
|
||||
await knex.schema.createTable(TableName.ServiceToken, (t) => {
|
||||
t.string("id", 36).primary().defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.jsonb("scopes").notNullable();
|
||||
t.specificType("permissions", "text[]").notNullable();
|
||||
t.datetime("lastUsed");
|
||||
t.datetime("expiresAt");
|
||||
t.text("secretHash").notNullable();
|
||||
t.text("encryptedKey");
|
||||
t.text("iv");
|
||||
t.text("tag");
|
||||
t.timestamps(true, true, true);
|
||||
// user is old one
|
||||
t.string("createdBy").notNullable();
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.ServiceToken);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.ServiceToken);
|
||||
await dropOnUpdateTrigger(knex, TableName.ServiceToken);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.Webhook))) {
|
||||
await knex.schema.createTable(TableName.Webhook, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("secretPath").notNullable().defaultTo("/");
|
||||
t.string("url").notNullable();
|
||||
t.string("lastStatus");
|
||||
t.text("lastRunErrorMessage");
|
||||
t.boolean("isDisabled").defaultTo(false).notNullable();
|
||||
// webhook signature
|
||||
t.text("encryptedSecretKey");
|
||||
t.text("iv");
|
||||
t.text("tag");
|
||||
t.string("algorithm");
|
||||
t.string("keyEncoding");
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.Webhook);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.Webhook);
|
||||
await dropOnUpdateTrigger(knex, TableName.Webhook);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.Identity))) {
|
||||
await knex.schema.createTable(TableName.Identity, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("authMethod");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.Identity);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.Identity);
|
||||
await dropOnUpdateTrigger(knex, TableName.Identity);
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityUniversalAuth))) {
|
||||
await knex.schema.createTable(TableName.IdentityUniversalAuth, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("clientId").notNullable();
|
||||
t.bigint("accessTokenTTL").defaultTo(7200).notNullable();
|
||||
t.bigint("accessTokenMaxTTL").defaultTo(7200).notNullable();
|
||||
t.bigint("accessTokenNumUsesLimit").defaultTo(0).notNullable();
|
||||
t.jsonb("clientSecretTrustedIps").notNullable();
|
||||
t.jsonb("accessTokenTrustedIps").notNullable();
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("identityId").notNullable().unique();
|
||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityUaClientSecret))) {
|
||||
await knex.schema.createTable(TableName.IdentityUaClientSecret, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("description").notNullable();
|
||||
t.string("clientSecretPrefix").notNullable();
|
||||
t.string("clientSecretHash").notNullable();
|
||||
t.datetime("clientSecretLastUsedAt");
|
||||
t.bigint("clientSecretNumUses").defaultTo(0).notNullable();
|
||||
t.bigint("clientSecretNumUsesLimit").defaultTo(0).notNullable();
|
||||
t.bigint("clientSecretTTL").defaultTo(0).notNullable();
|
||||
t.boolean("isClientSecretRevoked").defaultTo(false).notNullable();
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("identityUAId").notNullable();
|
||||
t.foreign("identityUAId")
|
||||
.references("id")
|
||||
.inTable(TableName.IdentityUniversalAuth)
|
||||
.onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityUniversalAuth);
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityUaClientSecret);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityUaClientSecret);
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityUniversalAuth);
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityUaClientSecret);
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityUniversalAuth);
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityAccessToken))) {
|
||||
await knex.schema.createTable(TableName.IdentityAccessToken, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.integer("accessTokenTTL").defaultTo(2592000).notNullable(); // 30 days second
|
||||
t.integer("accessTokenMaxTTL").defaultTo(2592000).notNullable();
|
||||
t.integer("accessTokenNumUses").defaultTo(0).notNullable();
|
||||
t.integer("accessTokenNumUsesLimit").defaultTo(0).notNullable();
|
||||
t.datetime("accessTokenLastUsedAt");
|
||||
t.datetime("accessTokenLastRenewedAt");
|
||||
t.boolean("isAccessTokenRevoked").defaultTo(false).notNullable();
|
||||
t.uuid("identityUAClientSecretId");
|
||||
t.foreign("identityUAClientSecretId")
|
||||
.references("id")
|
||||
.inTable(TableName.IdentityUaClientSecret)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("identityId").notNullable();
|
||||
t.foreign("identityId")
|
||||
.references("id")
|
||||
.inTable(TableName.Identity)
|
||||
.onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityAccessToken);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityAccessToken);
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityAccessToken);
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityOrgMembership))) {
|
||||
await knex.schema.createTable(TableName.IdentityOrgMembership, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("role").notNullable();
|
||||
t.uuid("roleId");
|
||||
t.foreign("roleId").references("id").inTable(TableName.OrgRoles);
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("identityId").notNullable();
|
||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityOrgMembership);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.IdentityProjectMembership))) {
|
||||
await knex.schema.createTable(TableName.IdentityProjectMembership, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("role").notNullable();
|
||||
t.uuid("roleId");
|
||||
t.foreign("roleId").references("id").inTable(TableName.ProjectRoles);
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
t.uuid("identityId").notNullable();
|
||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.IdentityProjectMembership);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityOrgMembership);
|
||||
await knex.schema.dropTableIfExists(TableName.IdentityProjectMembership);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityProjectMembership);
|
||||
await dropOnUpdateTrigger(knex, TableName.IdentityOrgMembership);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretApprovalPolicy))) {
|
||||
await knex.schema.createTable(TableName.SecretApprovalPolicy, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.string("secretPath");
|
||||
t.integer("approvals").defaultTo(1).notNullable();
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalPolicy);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretApprovalPolicyApprover))) {
|
||||
await knex.schema.createTable(TableName.SecretApprovalPolicyApprover, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("approverId").notNullable();
|
||||
t.foreign("approverId")
|
||||
.references("id")
|
||||
.inTable(TableName.ProjectMembership)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("policyId").notNullable();
|
||||
t.foreign("policyId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretApprovalPolicy)
|
||||
.onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalPolicyApprover);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretApprovalPolicyApprover);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretApprovalPolicy);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretApprovalPolicyApprover);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretApprovalPolicy);
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { SecretEncryptionAlgo, SecretKeyEncoding, TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretApprovalRequest))) {
|
||||
await knex.schema.createTable(TableName.SecretApprovalRequest, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("policyId").notNullable();
|
||||
t.boolean("hasMerged").defaultTo(false).notNullable();
|
||||
t.string("status").defaultTo("open").notNullable();
|
||||
t.jsonb("conflicts");
|
||||
t.foreign("policyId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretApprovalPolicy)
|
||||
.onDelete("CASCADE");
|
||||
t.string("slug").notNullable();
|
||||
t.uuid("folderId").notNullable();
|
||||
t.foreign("folderId").references("id").inTable(TableName.SecretFolder).onDelete("CASCADE");
|
||||
t.uuid("statusChangeBy");
|
||||
t.foreign("statusChangeBy")
|
||||
.references("id")
|
||||
.inTable(TableName.ProjectMembership)
|
||||
.onDelete("SET NULL");
|
||||
t.uuid("committerId").notNullable();
|
||||
t.foreign("committerId")
|
||||
.references("id")
|
||||
.inTable(TableName.ProjectMembership)
|
||||
.onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequest);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretApprovalRequestReviewer))) {
|
||||
await knex.schema.createTable(TableName.SecretApprovalRequestReviewer, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("member").notNullable();
|
||||
t.foreign("member").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE");
|
||||
t.string("status").notNullable();
|
||||
t.uuid("requestId").notNullable();
|
||||
t.foreign("requestId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretApprovalRequest)
|
||||
.onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequestReviewer);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretApprovalRequestSecret))) {
|
||||
await knex.schema.createTable(TableName.SecretApprovalRequestSecret, (t) => {
|
||||
// everything related to secret
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.integer("version").defaultTo(1);
|
||||
t.text("secretBlindIndex");
|
||||
t.text("secretKeyCiphertext").notNullable();
|
||||
t.text("secretKeyIV").notNullable();
|
||||
t.text("secretKeyTag").notNullable();
|
||||
t.text("secretValueCiphertext").notNullable();
|
||||
t.text("secretValueIV").notNullable(); // symmetric encryption
|
||||
t.text("secretValueTag").notNullable();
|
||||
t.text("secretCommentCiphertext");
|
||||
t.text("secretCommentIV");
|
||||
t.text("secretCommentTag");
|
||||
t.string("secretReminderNote");
|
||||
t.integer("secretReminderRepeatDays");
|
||||
t.boolean("skipMultilineEncoding").defaultTo(false);
|
||||
t.string("algorithm").notNullable().defaultTo(SecretEncryptionAlgo.AES_256_GCM);
|
||||
t.string("keyEncoding").notNullable().defaultTo(SecretKeyEncoding.UTF8);
|
||||
t.jsonb("metadata");
|
||||
t.timestamps(true, true, true);
|
||||
// commit details
|
||||
t.uuid("requestId").notNullable();
|
||||
t.foreign("requestId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretApprovalRequest)
|
||||
.onDelete("CASCADE");
|
||||
t.string("op").notNullable();
|
||||
t.uuid("secretId");
|
||||
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("SET NULL");
|
||||
t.uuid("secretVersion");
|
||||
t.foreign("secretVersion")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretVersion)
|
||||
.onDelete("SET NULL");
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecret);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretApprovalRequestSecretTag))) {
|
||||
await knex.schema.createTable(TableName.SecretApprovalRequestSecretTag, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("secretId").notNullable();
|
||||
t.foreign("secretId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretApprovalRequestSecret)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("tagId").notNullable();
|
||||
t.foreign("tagId").references("id").inTable(TableName.SecretTag).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecretTag);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretApprovalRequestSecretTag);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretApprovalRequestSecret);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretApprovalRequestReviewer);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretApprovalRequest);
|
||||
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecretTag);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretApprovalRequestSecret);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretApprovalRequestReviewer);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretApprovalRequest);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SecretRotation))) {
|
||||
await knex.schema.createTable(TableName.SecretRotation, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("provider").notNullable();
|
||||
t.string("secretPath").notNullable();
|
||||
t.integer("interval").notNullable();
|
||||
t.datetime("lastRotatedAt");
|
||||
t.string("status");
|
||||
t.text("statusMessage");
|
||||
t.text("encryptedData");
|
||||
t.text("encryptedDataIV");
|
||||
t.text("encryptedDataTag");
|
||||
t.string("algorithm");
|
||||
t.string("keyEncoding");
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.SecretRotation);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretRotationOutput))) {
|
||||
await knex.schema.createTable(TableName.SecretRotationOutput, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("key").notNullable();
|
||||
t.uuid("secretId").notNullable();
|
||||
t.foreign("secretId").references("id").inTable(TableName.Secret).onDelete("CASCADE");
|
||||
t.uuid("rotationId").notNullable();
|
||||
t.foreign("rotationId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretRotation)
|
||||
.onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretRotationOutput);
|
||||
await knex.schema.dropTableIfExists(TableName.SecretRotation);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretRotation);
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.Snapshot))) {
|
||||
await knex.schema.createTable(TableName.Snapshot, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
// this is not a relation kept like that
|
||||
// this ensure snapshot are not lost when folder gets deleted and rolled back
|
||||
t.uuid("folderId").notNullable();
|
||||
t.uuid("parentFolderId");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.Snapshot);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SnapshotSecret))) {
|
||||
await knex.schema.createTable(TableName.SnapshotSecret, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
// not a relation kept like that to keep it when rolled back
|
||||
t.uuid("secretVersionId").notNullable();
|
||||
t.foreign("secretVersionId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretVersion)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("snapshotId").notNullable();
|
||||
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SnapshotFolder))) {
|
||||
await knex.schema.createTable(TableName.SnapshotFolder, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("envId").notNullable();
|
||||
t.foreign("envId").references("id").inTable(TableName.Environment).onDelete("CASCADE");
|
||||
// not a relation kept like that to keep it when rolled back
|
||||
t.uuid("folderVersionId").notNullable();
|
||||
t.foreign("folderVersionId")
|
||||
.references("id")
|
||||
.inTable(TableName.SecretFolderVersion)
|
||||
.onDelete("CASCADE");
|
||||
t.uuid("snapshotId").notNullable();
|
||||
t.foreign("snapshotId").references("id").inTable(TableName.Snapshot).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SnapshotSecret);
|
||||
await knex.schema.dropTableIfExists(TableName.SnapshotFolder);
|
||||
await knex.schema.dropTableIfExists(TableName.Snapshot);
|
||||
await dropOnUpdateTrigger(knex, TableName.Snapshot);
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.SamlConfig))) {
|
||||
await knex.schema.createTable(TableName.SamlConfig, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("authProvider").notNullable();
|
||||
t.boolean("isActive").notNullable();
|
||||
t.string("encryptedEntryPoint");
|
||||
t.string("entryPointIV");
|
||||
t.string("entryPointTag");
|
||||
t.string("encryptedIssuer");
|
||||
t.string("issuerTag");
|
||||
t.string("issuerIV");
|
||||
t.text("encryptedCert");
|
||||
t.string("certIV");
|
||||
t.string("certTag");
|
||||
t.timestamps(true, true, true);
|
||||
t.uuid("orgId").notNullable().unique();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization);
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.SamlConfig);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SamlConfig);
|
||||
await dropOnUpdateTrigger(knex, TableName.SamlConfig);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.OrgBot))) {
|
||||
await knex.schema.createTable(TableName.OrgBot, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("name").notNullable();
|
||||
t.text("publicKey").notNullable();
|
||||
t.text("encryptedSymmetricKey").notNullable();
|
||||
t.text("symmetricKeyIV").notNullable();
|
||||
t.text("symmetricKeyTag").notNullable();
|
||||
t.string("symmetricKeyAlgorithm").notNullable();
|
||||
t.string("symmetricKeyKeyEncoding").notNullable();
|
||||
t.text("encryptedPrivateKey").notNullable();
|
||||
t.text("privateKeyIV").notNullable();
|
||||
t.text("privateKeyTag").notNullable();
|
||||
t.string("privateKeyAlgorithm").notNullable();
|
||||
t.string("privateKeyKeyEncoding").notNullable();
|
||||
// one to one relationship
|
||||
t.uuid("orgId").notNullable().unique();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
await createOnUpdateTrigger(knex, TableName.OrgBot);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.OrgBot);
|
||||
await dropOnUpdateTrigger(knex, TableName.OrgBot);
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.AuditLog))) {
|
||||
await knex.schema.createTable(TableName.AuditLog, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("actor").notNullable();
|
||||
t.jsonb("actorMetadata").notNullable();
|
||||
t.string("ipAddress");
|
||||
t.string("eventType").notNullable();
|
||||
t.jsonb("eventMetadata");
|
||||
t.string("userAgent");
|
||||
t.string("userAgentType");
|
||||
t.datetime("expiresAt");
|
||||
t.timestamps(true, true, true);
|
||||
// no trigger needed as this collection is append only
|
||||
t.uuid("orgId");
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.string("projectId");
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.AuditLog);
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.GitAppInstallSession))) {
|
||||
await knex.schema.createTable(TableName.GitAppInstallSession, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("sessionId").notNullable().unique();
|
||||
t.uuid("userId");
|
||||
// one to one relationship
|
||||
t.uuid("orgId").notNullable().unique();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
createOnUpdateTrigger(knex, TableName.GitAppInstallSession);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.GitAppOrg))) {
|
||||
await knex.schema.createTable(TableName.GitAppOrg, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("installationId").notNullable().unique();
|
||||
t.uuid("userId").notNullable();
|
||||
// one to one relationship
|
||||
t.uuid("orgId").notNullable().unique();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
createOnUpdateTrigger(knex, TableName.GitAppOrg);
|
||||
|
||||
if (!(await knex.schema.hasTable(TableName.SecretScanningGitRisk))) {
|
||||
await knex.schema.createTable(TableName.SecretScanningGitRisk, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("description");
|
||||
t.string("startLine");
|
||||
t.string("endLine");
|
||||
t.string("startColumn");
|
||||
t.string("endColumn");
|
||||
t.string("file");
|
||||
t.string("symlinkFile");
|
||||
t.string("commit");
|
||||
t.string("entropy");
|
||||
t.string("author");
|
||||
t.string("email");
|
||||
t.string("date");
|
||||
t.text("message");
|
||||
t.specificType("tags", "text[]");
|
||||
t.string("ruleID");
|
||||
t.string("fingerprint").unique();
|
||||
t.string("fingerPrintWithoutCommitId");
|
||||
t.boolean("isFalsePositive").defaultTo(false);
|
||||
t.boolean("isResolved").defaultTo(false);
|
||||
t.string("riskOwner");
|
||||
t.string("installationId").notNullable();
|
||||
t.string("repositoryId");
|
||||
t.string("repositoryLink");
|
||||
t.string("repositoryFullName");
|
||||
t.string("pusherName");
|
||||
t.string("pusherEmail");
|
||||
t.string("status");
|
||||
// one to one relationship
|
||||
t.uuid("orgId").notNullable();
|
||||
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
createOnUpdateTrigger(knex, TableName.SecretScanningGitRisk);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.SecretScanningGitRisk);
|
||||
await knex.schema.dropTableIfExists(TableName.GitAppOrg);
|
||||
await knex.schema.dropTableIfExists(TableName.GitAppInstallSession);
|
||||
await dropOnUpdateTrigger(knex, TableName.SecretScanningGitRisk);
|
||||
await dropOnUpdateTrigger(knex, TableName.GitAppOrg);
|
||||
await dropOnUpdateTrigger(knex, TableName.GitAppInstallSession);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.TrustedIps))) {
|
||||
await knex.schema.createTable(TableName.TrustedIps, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.string("ipAddress").notNullable();
|
||||
t.string("type").notNullable();
|
||||
t.integer("prefix");
|
||||
t.boolean("isActive").defaultTo(true);
|
||||
t.string("comment");
|
||||
t.string("projectId").notNullable();
|
||||
t.foreign("projectId").references("id").inTable(TableName.Project);
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
}
|
||||
await createOnUpdateTrigger(knex, TableName.TrustedIps);
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.TrustedIps);
|
||||
await dropOnUpdateTrigger(knex, TableName.TrustedIps);
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import { Schema, Types, model } from "mongoose";
|
||||
|
||||
export interface IAPIKeyData {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
user: Types.ObjectId;
|
||||
lastUsed: Date;
|
||||
expiresAt: Date;
|
||||
secretHash: string;
|
||||
}
|
||||
|
||||
const apiKeyDataSchema = new Schema<IAPIKeyData>(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
user: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
required: true,
|
||||
},
|
||||
lastUsed: {
|
||||
type: Date,
|
||||
},
|
||||
expiresAt: {
|
||||
type: Date,
|
||||
},
|
||||
secretHash: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
},
|
||||
);
|
||||
|
||||
export const APIKeyData = model<IAPIKeyData>("APIKeyData", apiKeyDataSchema);
|
@ -1,38 +0,0 @@
|
||||
import { Document, Schema, Types, model } from "mongoose";
|
||||
|
||||
export interface IAPIKeyDataV2 extends Document {
|
||||
_id: Types.ObjectId;
|
||||
name: string;
|
||||
user: Types.ObjectId;
|
||||
lastUsed?: Date
|
||||
usageCount: number;
|
||||
expiresAt?: Date;
|
||||
}
|
||||
|
||||
const apiKeyDataV2Schema = new Schema(
|
||||
{
|
||||
name: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
user: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: "User",
|
||||
required: true
|
||||
},
|
||||
lastUsed: {
|
||||
type: Date,
|
||||
required: false
|
||||
},
|
||||
usageCount: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
{
|
||||
timestamps: true
|
||||
}
|
||||
);
|
||||
|
||||
export const APIKeyDataV2 = model<IAPIKeyDataV2>("APIKeyDataV2", apiKeyDataV2Schema);
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user