mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 19:28:09 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -74,21 +74,21 @@ jobs:
|
|||||||
uses: pr-mpt/actions-commit-hash@v2
|
uses: pr-mpt/actions-commit-hash@v2
|
||||||
- name: Download task definition
|
- name: Download task definition
|
||||||
run: |
|
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
|
- name: Render Amazon ECS task definition
|
||||||
id: render-web-container
|
id: render-web-container
|
||||||
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
uses: aws-actions/amazon-ecs-render-task-definition@v1
|
||||||
with:
|
with:
|
||||||
task-definition: task-definition.json
|
task-definition: task-definition.json
|
||||||
container-name: infisical-prod-platform
|
container-name: infisical-core-platform
|
||||||
image: infisical/staging_infisical:${{ steps.commit.outputs.short }}
|
image: infisical/staging_infisical:${{ steps.commit.outputs.short }}
|
||||||
environment-variables: "LOG_LEVEL=info"
|
environment-variables: "LOG_LEVEL=info"
|
||||||
- name: Deploy to Amazon ECS service
|
- name: Deploy to Amazon ECS service
|
||||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||||
with:
|
with:
|
||||||
task-definition: ${{ steps.render-web-container.outputs.task-definition }}
|
task-definition: ${{ steps.render-web-container.outputs.task-definition }}
|
||||||
service: infisical-prod-platform
|
service: infisical-core-platform
|
||||||
cluster: infisical-prod-platform
|
cluster: infisical-core-platform
|
||||||
wait-for-service-stability: true
|
wait-for-service-stability: true
|
||||||
|
|
||||||
production-postgres-deployment:
|
production-postgres-deployment:
|
||||||
@@ -135,6 +135,6 @@ jobs:
|
|||||||
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
|
||||||
with:
|
with:
|
||||||
task-definition: ${{ steps.render-web-container.outputs.task-definition }}
|
task-definition: ${{ steps.render-web-container.outputs.task-definition }}
|
||||||
service: infisical-prod-platform
|
service: infisical-core-platform
|
||||||
cluster: infisical-prod-platform
|
cluster: infisical-core-platform
|
||||||
wait-for-service-stability: true
|
wait-for-service-stability: true
|
||||||
|
|||||||
Vendored
+2
-2
@@ -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 { TGroupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
||||||
import { TIdentityServiceFactory } from "@app/services/identity/identity-service";
|
import { TIdentityServiceFactory } from "@app/services/identity/identity-service";
|
||||||
import { TIdentityAccessTokenServiceFactory } from "@app/services/identity-access-token/identity-access-token-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 { TIdentityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service";
|
||||||
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
||||||
import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
|
import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
|
||||||
@@ -118,7 +118,7 @@ declare module "fastify" {
|
|||||||
identityProject: TIdentityProjectServiceFactory;
|
identityProject: TIdentityProjectServiceFactory;
|
||||||
identityUa: TIdentityUaServiceFactory;
|
identityUa: TIdentityUaServiceFactory;
|
||||||
identityGcpAuth: TIdentityGcpAuthServiceFactory;
|
identityGcpAuth: TIdentityGcpAuthServiceFactory;
|
||||||
identityAwsIamAuth: TIdentityAwsIamAuthServiceFactory;
|
identityAwsAuth: TIdentityAwsAuthServiceFactory;
|
||||||
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
|
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
|
||||||
accessApprovalRequest: TAccessApprovalRequestServiceFactory;
|
accessApprovalRequest: TAccessApprovalRequestServiceFactory;
|
||||||
secretApprovalPolicy: TSecretApprovalPolicyServiceFactory;
|
secretApprovalPolicy: TSecretApprovalPolicyServiceFactory;
|
||||||
|
|||||||
Vendored
+7
-7
@@ -59,9 +59,9 @@ import {
|
|||||||
TIdentityAccessTokens,
|
TIdentityAccessTokens,
|
||||||
TIdentityAccessTokensInsert,
|
TIdentityAccessTokensInsert,
|
||||||
TIdentityAccessTokensUpdate,
|
TIdentityAccessTokensUpdate,
|
||||||
TIdentityAwsIamAuths,
|
TIdentityAwsAuths,
|
||||||
TIdentityAwsIamAuthsInsert,
|
TIdentityAwsAuthsInsert,
|
||||||
TIdentityAwsIamAuthsUpdate,
|
TIdentityAwsAuthsUpdate,
|
||||||
TIdentityGcpAuths,
|
TIdentityGcpAuths,
|
||||||
TIdentityGcpAuthsInsert,
|
TIdentityGcpAuthsInsert,
|
||||||
TIdentityGcpAuthsUpdate,
|
TIdentityGcpAuthsUpdate,
|
||||||
@@ -337,10 +337,10 @@ declare module "knex/types/tables" {
|
|||||||
TIdentityGcpAuthsInsert,
|
TIdentityGcpAuthsInsert,
|
||||||
TIdentityGcpAuthsUpdate
|
TIdentityGcpAuthsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.IdentityAwsIamAuth]: Knex.CompositeTableType<
|
[TableName.IdentityAwsAuth]: Knex.CompositeTableType<
|
||||||
TIdentityAwsIamAuths,
|
TIdentityAwsAuths,
|
||||||
TIdentityAwsIamAuthsInsert,
|
TIdentityAwsAuthsInsert,
|
||||||
TIdentityAwsIamAuthsUpdate
|
TIdentityAwsAuthsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
||||||
TIdentityUaClientSecrets,
|
TIdentityUaClientSecrets,
|
||||||
|
|||||||
+6
-5
@@ -4,8 +4,8 @@ import { TableName } from "../schemas";
|
|||||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
if (!(await knex.schema.hasTable(TableName.IdentityAwsIamAuth))) {
|
if (!(await knex.schema.hasTable(TableName.IdentityAwsAuth))) {
|
||||||
await knex.schema.createTable(TableName.IdentityAwsIamAuth, (t) => {
|
await knex.schema.createTable(TableName.IdentityAwsAuth, (t) => {
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
|
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
|
||||||
t.bigInteger("accessTokenMaxTTL").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.timestamps(true, true, true);
|
||||||
t.uuid("identityId").notNullable().unique();
|
t.uuid("identityId").notNullable().unique();
|
||||||
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
|
||||||
|
t.string("type").notNullable();
|
||||||
t.string("stsEndpoint").notNullable();
|
t.string("stsEndpoint").notNullable();
|
||||||
t.string("allowedPrincipalArns").notNullable();
|
t.string("allowedPrincipalArns").notNullable();
|
||||||
t.string("allowedAccountIds").notNullable();
|
t.string("allowedAccountIds").notNullable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await createOnUpdateTrigger(knex, TableName.IdentityAwsIamAuth);
|
await createOnUpdateTrigger(knex, TableName.IdentityAwsAuth);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
await knex.schema.dropTableIfExists(TableName.IdentityAwsIamAuth);
|
await knex.schema.dropTableIfExists(TableName.IdentityAwsAuth);
|
||||||
await dropOnUpdateTrigger(knex, TableName.IdentityAwsIamAuth);
|
await dropOnUpdateTrigger(knex, TableName.IdentityAwsAuth);
|
||||||
}
|
}
|
||||||
+5
-4
@@ -7,7 +7,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
export const IdentityAwsIamAuthsSchema = z.object({
|
export const IdentityAwsAuthsSchema = z.object({
|
||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
accessTokenTTL: z.coerce.number().default(7200),
|
accessTokenTTL: z.coerce.number().default(7200),
|
||||||
accessTokenMaxTTL: z.coerce.number().default(7200),
|
accessTokenMaxTTL: z.coerce.number().default(7200),
|
||||||
@@ -16,11 +16,12 @@ export const IdentityAwsIamAuthsSchema = z.object({
|
|||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
identityId: z.string().uuid(),
|
identityId: z.string().uuid(),
|
||||||
|
type: z.string(),
|
||||||
stsEndpoint: z.string(),
|
stsEndpoint: z.string(),
|
||||||
allowedPrincipalArns: z.string(),
|
allowedPrincipalArns: z.string(),
|
||||||
allowedAccountIds: z.string()
|
allowedAccountIds: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TIdentityAwsIamAuths = z.infer<typeof IdentityAwsIamAuthsSchema>;
|
export type TIdentityAwsAuths = z.infer<typeof IdentityAwsAuthsSchema>;
|
||||||
export type TIdentityAwsIamAuthsInsert = Omit<z.input<typeof IdentityAwsIamAuthsSchema>, TImmutableDBKeys>;
|
export type TIdentityAwsAuthsInsert = Omit<z.input<typeof IdentityAwsAuthsSchema>, TImmutableDBKeys>;
|
||||||
export type TIdentityAwsIamAuthsUpdate = Partial<Omit<z.input<typeof IdentityAwsIamAuthsSchema>, 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 "./groups";
|
||||||
export * from "./identities";
|
export * from "./identities";
|
||||||
export * from "./identity-access-tokens";
|
export * from "./identity-access-tokens";
|
||||||
export * from "./identity-aws-iam-auths";
|
export * from "./identity-aws-auths";
|
||||||
export * from "./identity-gcp-auths";
|
export * from "./identity-gcp-auths";
|
||||||
export * from "./identity-org-memberships";
|
export * from "./identity-org-memberships";
|
||||||
export * from "./identity-project-additional-privilege";
|
export * from "./identity-project-additional-privilege";
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export enum TableName {
|
|||||||
IdentityUniversalAuth = "identity_universal_auths",
|
IdentityUniversalAuth = "identity_universal_auths",
|
||||||
IdentityGcpAuth = "identity_gcp_auths",
|
IdentityGcpAuth = "identity_gcp_auths",
|
||||||
IdentityUaClientSecret = "identity_ua_client_secrets",
|
IdentityUaClientSecret = "identity_ua_client_secrets",
|
||||||
IdentityAwsIamAuth = "identity_aws_iam_auths",
|
IdentityAwsAuth = "identity_aws_auths",
|
||||||
IdentityOrgMembership = "identity_org_memberships",
|
IdentityOrgMembership = "identity_org_memberships",
|
||||||
IdentityProjectMembership = "identity_project_memberships",
|
IdentityProjectMembership = "identity_project_memberships",
|
||||||
IdentityProjectMembershipRole = "identity_project_membership_role",
|
IdentityProjectMembershipRole = "identity_project_membership_role",
|
||||||
@@ -146,5 +146,5 @@ export enum ProjectUpgradeStatus {
|
|||||||
export enum IdentityAuthMethod {
|
export enum IdentityAuthMethod {
|
||||||
Univeral = "universal-auth",
|
Univeral = "universal-auth",
|
||||||
GCP_AUTH = "gcp-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",
|
ADD_IDENTITY_GCP_AUTH = "add-identity-gcp -auth",
|
||||||
UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth",
|
UPDATE_IDENTITY_GCP_AUTH = "update-identity-gcp-auth",
|
||||||
GET_IDENTITY_GCP_AUTH = "get-identity-gcp-auth",
|
GET_IDENTITY_GCP_AUTH = "get-identity-gcp-auth",
|
||||||
LOGIN_IDENTITY_AWS_IAM_AUTH = "login-identity-aws-iam-auth",
|
LOGIN_IDENTITY_AWS_AUTH = "login-identity-aws-auth",
|
||||||
ADD_IDENTITY_AWS_IAM_AUTH = "add-identity-aws-iam-auth",
|
ADD_IDENTITY_AWS_AUTH = "add-identity-aws-auth",
|
||||||
UPDATE_IDENTITY_AWS_IAM_AUTH = "update-identity-aws-iam-auth",
|
UPDATE_IDENTITY_AWS_AUTH = "update-identity-aws-auth",
|
||||||
GET_IDENTITY_AWS_IAM_AUTH = "get-identity-aws-iam-auth",
|
GET_IDENTITY_AWS_AUTH = "get-identity-aws-auth",
|
||||||
CREATE_ENVIRONMENT = "create-environment",
|
CREATE_ENVIRONMENT = "create-environment",
|
||||||
UPDATE_ENVIRONMENT = "update-environment",
|
UPDATE_ENVIRONMENT = "update-environment",
|
||||||
DELETE_ENVIRONMENT = "delete-environment",
|
DELETE_ENVIRONMENT = "delete-environment",
|
||||||
@@ -460,17 +460,17 @@ interface GetIdentityGcpAuthEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoginIdentityAwsIamAuthEvent {
|
interface LoginIdentityAwsAuthEvent {
|
||||||
type: EventType.LOGIN_IDENTITY_AWS_IAM_AUTH;
|
type: EventType.LOGIN_IDENTITY_AWS_AUTH;
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
identityAwsIamAuthId: string;
|
identityAwsAuthId: string;
|
||||||
identityAccessTokenId: string;
|
identityAccessTokenId: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AddIdentityAwsIamAuthEvent {
|
interface AddIdentityAwsAuthEvent {
|
||||||
type: EventType.ADD_IDENTITY_AWS_IAM_AUTH;
|
type: EventType.ADD_IDENTITY_AWS_AUTH;
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint: string;
|
stsEndpoint: string;
|
||||||
@@ -483,8 +483,8 @@ interface AddIdentityAwsIamAuthEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface UpdateIdentityAwsIamAuthEvent {
|
interface UpdateIdentityAwsAuthEvent {
|
||||||
type: EventType.UPDATE_IDENTITY_AWS_IAM_AUTH;
|
type: EventType.UPDATE_IDENTITY_AWS_AUTH;
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint?: string;
|
stsEndpoint?: string;
|
||||||
@@ -497,8 +497,8 @@ interface UpdateIdentityAwsIamAuthEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetIdentityAwsIamAuthEvent {
|
interface GetIdentityAwsAuthEvent {
|
||||||
type: EventType.GET_IDENTITY_AWS_IAM_AUTH;
|
type: EventType.GET_IDENTITY_AWS_AUTH;
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
};
|
};
|
||||||
@@ -762,10 +762,10 @@ export type Event =
|
|||||||
| AddIdentityGcpAuthEvent
|
| AddIdentityGcpAuthEvent
|
||||||
| UpdateIdentityGcpAuthEvent
|
| UpdateIdentityGcpAuthEvent
|
||||||
| GetIdentityGcpAuthEvent
|
| GetIdentityGcpAuthEvent
|
||||||
| LoginIdentityAwsIamAuthEvent
|
| LoginIdentityAwsAuthEvent
|
||||||
| AddIdentityAwsIamAuthEvent
|
| AddIdentityAwsAuthEvent
|
||||||
| UpdateIdentityAwsIamAuthEvent
|
| UpdateIdentityAwsAuthEvent
|
||||||
| GetIdentityAwsIamAuthEvent
|
| GetIdentityAwsAuthEvent
|
||||||
| CreateEnvironmentEvent
|
| CreateEnvironmentEvent
|
||||||
| UpdateEnvironmentEvent
|
| UpdateEnvironmentEvent
|
||||||
| DeleteEnvironmentEvent
|
| DeleteEnvironmentEvent
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export const UNIVERSAL_AUTH = {
|
|||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const AWS_IAM_AUTH = {
|
export const AWS_AUTH = {
|
||||||
LOGIN: {
|
LOGIN: {
|
||||||
identityId: "The ID of the identity to login.",
|
identityId: "The ID of the identity to login.",
|
||||||
iamHttpRequestMethod: "The HTTP request method used in the signed request.",
|
iamHttpRequestMethod: "The HTTP request method used in the signed request.",
|
||||||
@@ -288,7 +288,8 @@ export const RAW_SECRETS = {
|
|||||||
recursive:
|
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.",
|
"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.",
|
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.",
|
environment: "The slug of the environment to list secrets from.",
|
||||||
secretPath: "The secret path to list secrets from.",
|
secretPath: "The secret path to list secrets from.",
|
||||||
includeImports: "Weather to include imported secrets or not."
|
includeImports: "Weather to include imported secrets or not."
|
||||||
@@ -307,6 +308,7 @@ export const RAW_SECRETS = {
|
|||||||
GET: {
|
GET: {
|
||||||
secretName: "The name of the secret to get.",
|
secretName: "The name of the secret to get.",
|
||||||
workspaceId: "The ID of the project to get the secret from.",
|
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.",
|
environment: "The slug of the environment to get the secret from.",
|
||||||
secretPath: "The path of the secret to get.",
|
secretPath: "The path of the secret to get.",
|
||||||
version: "The version 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.",
|
shouldAutoRedeploy: "Used by Render to trigger auto deploy.",
|
||||||
secretGCPLabel: "The label for GCP secrets.",
|
secretGCPLabel: "The label for GCP secrets.",
|
||||||
secretAWSTag: "The tags for AWS 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: {
|
UPDATE: {
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ import { identityOrgDALFactory } from "@app/services/identity/identity-org-dal";
|
|||||||
import { identityServiceFactory } from "@app/services/identity/identity-service";
|
import { identityServiceFactory } from "@app/services/identity/identity-service";
|
||||||
import { identityAccessTokenDALFactory } from "@app/services/identity-access-token/identity-access-token-dal";
|
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 { 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 { identityAwsAuthDALFactory } from "@app/services/identity-aws-auth/identity-aws-auth-dal";
|
||||||
import { identityAwsIamAuthServiceFactory } from "@app/services/identity-aws-iam-auth/identity-aws-iam-auth-service";
|
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 { identityGcpAuthDALFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-dal";
|
||||||
import { identityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service";
|
import { identityGcpAuthServiceFactory } from "@app/services/identity-gcp-auth/identity-gcp-auth-service";
|
||||||
import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
||||||
@@ -205,7 +205,7 @@ export const registerRoutes = async (
|
|||||||
|
|
||||||
const identityUaDAL = identityUaDALFactory(db);
|
const identityUaDAL = identityUaDALFactory(db);
|
||||||
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
|
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
|
||||||
const identityAwsIamAuthDAL = identityAwsIamAuthDALFactory(db);
|
const identityAwsAuthDAL = identityAwsAuthDALFactory(db);
|
||||||
|
|
||||||
const identityGcpAuthDAL = identityGcpAuthDALFactory(db);
|
const identityGcpAuthDAL = identityGcpAuthDALFactory(db);
|
||||||
|
|
||||||
@@ -716,9 +716,9 @@ export const registerRoutes = async (
|
|||||||
licenseService
|
licenseService
|
||||||
});
|
});
|
||||||
|
|
||||||
const identityAWSIAMAuthService = identityAwsIamAuthServiceFactory({
|
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityAwsIamAuthDAL,
|
identityAwsAuthDAL,
|
||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
identityDAL,
|
identityDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
@@ -794,7 +794,7 @@ export const registerRoutes = async (
|
|||||||
identityProject: identityProjectService,
|
identityProject: identityProjectService,
|
||||||
identityUa: identityUaService,
|
identityUa: identityUaService,
|
||||||
identityGcpAuth: identityGcpAuthService,
|
identityGcpAuth: identityGcpAuthService,
|
||||||
identityAwsIamAuth: identityAWSIAMAuthService,
|
identityAwsAuth: identityAwsAuthService,
|
||||||
secretApprovalPolicy: sapService,
|
secretApprovalPolicy: sapService,
|
||||||
accessApprovalPolicy: accessApprovalPolicyService,
|
accessApprovalPolicy: accessApprovalPolicyService,
|
||||||
accessApprovalRequest: accessApprovalRequestService,
|
accessApprovalRequest: accessApprovalRequestService,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { z } from "zod";
|
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 { 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 { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
@@ -10,22 +10,22 @@ import { TIdentityTrustedIp } from "@app/services/identity/identity-types";
|
|||||||
import {
|
import {
|
||||||
validateAccountIds,
|
validateAccountIds,
|
||||||
validatePrincipalArns
|
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({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/aws-iam-auth/login",
|
url: "/aws-auth/login",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
description: "Login with AWS IAM Auth",
|
description: "Login with AWS Auth",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
identityId: z.string().describe(AWS_IAM_AUTH.LOGIN.identityId),
|
identityId: z.string().describe(AWS_AUTH.LOGIN.identityId),
|
||||||
iamHttpRequestMethod: z.string().default("POST").describe(AWS_IAM_AUTH.LOGIN.iamHttpRequestMethod),
|
iamHttpRequestMethod: z.string().default("POST").describe(AWS_AUTH.LOGIN.iamHttpRequestMethod),
|
||||||
iamRequestBody: z.string().describe(AWS_IAM_AUTH.LOGIN.iamRequestBody),
|
iamRequestBody: z.string().describe(AWS_AUTH.LOGIN.iamRequestBody),
|
||||||
iamRequestHeaders: z.string().describe(AWS_IAM_AUTH.LOGIN.iamRequestHeaders)
|
iamRequestHeaders: z.string().describe(AWS_AUTH.LOGIN.iamRequestHeaders)
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -37,18 +37,18 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityAwsIamAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityAwsAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
||||||
await server.services.identityAwsIamAuth.login(req.body);
|
await server.services.identityAwsAuth.login(req.body);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg?.orgId,
|
orgId: identityMembershipOrg?.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_AWS_IAM_AUTH,
|
type: EventType.LOGIN_IDENTITY_AWS_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: identityAwsIamAuth.identityId,
|
identityId: identityAwsAuth.identityId,
|
||||||
identityAccessTokenId: identityAccessToken.id,
|
identityAccessTokenId: identityAccessToken.id,
|
||||||
identityAwsIamAuthId: identityAwsIamAuth.id
|
identityAwsAuthId: identityAwsAuth.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -56,21 +56,21 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
return {
|
return {
|
||||||
accessToken,
|
accessToken,
|
||||||
tokenType: "Bearer" as const,
|
tokenType: "Bearer" as const,
|
||||||
expiresIn: identityAwsIamAuth.accessTokenTTL,
|
expiresIn: identityAwsAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL
|
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/aws-iam-auth/identities/:identityId",
|
url: "/aws-auth/identities/:identityId",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
description: "Attach AWS IAM Auth configuration onto identity",
|
description: "Attach AWS Auth configuration onto identity",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
@@ -109,12 +109,12 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
identityAwsIamAuth: IdentityAwsIamAuthsSchema
|
identityAwsAuth: IdentityAwsAuthsSchema
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const identityAwsIamAuth = await server.services.identityAwsIamAuth.attachAwsIamAuth({
|
const identityAwsAuth = await server.services.identityAwsAuth.attachAwsAuth({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
@@ -125,35 +125,35 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityAwsIamAuth.orgId,
|
orgId: identityAwsAuth.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.ADD_IDENTITY_AWS_IAM_AUTH,
|
type: EventType.ADD_IDENTITY_AWS_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: identityAwsIamAuth.identityId,
|
identityId: identityAwsAuth.identityId,
|
||||||
stsEndpoint: identityAwsIamAuth.stsEndpoint,
|
stsEndpoint: identityAwsAuth.stsEndpoint,
|
||||||
allowedPrincipalArns: identityAwsIamAuth.allowedPrincipalArns,
|
allowedPrincipalArns: identityAwsAuth.allowedPrincipalArns,
|
||||||
allowedAccountIds: identityAwsIamAuth.allowedAccountIds,
|
allowedAccountIds: identityAwsAuth.allowedAccountIds,
|
||||||
accessTokenTTL: identityAwsIamAuth.accessTokenTTL,
|
accessTokenTTL: identityAwsAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||||
accessTokenTrustedIps: identityAwsIamAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
accessTokenTrustedIps: identityAwsAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
accessTokenNumUsesLimit: identityAwsIamAuth.accessTokenNumUsesLimit
|
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { identityAwsIamAuth };
|
return { identityAwsAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
url: "/aws-iam-auth/identities/:identityId",
|
url: "/aws-auth/identities/:identityId",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
description: "Update AWS IAM Auth configuration on identity",
|
description: "Update AWS Auth configuration on identity",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
@@ -185,12 +185,12 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
identityAwsIamAuth: IdentityAwsIamAuthsSchema
|
identityAwsAuth: IdentityAwsAuthsSchema
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const identityAwsIamAuth = await server.services.identityAwsIamAuth.updateAwsIamAuth({
|
const identityAwsAuth = await server.services.identityAwsAuth.updateAwsAuth({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
@@ -201,35 +201,35 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityAwsIamAuth.orgId,
|
orgId: identityAwsAuth.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.UPDATE_IDENTITY_AWS_IAM_AUTH,
|
type: EventType.UPDATE_IDENTITY_AWS_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
identityId: identityAwsIamAuth.identityId,
|
identityId: identityAwsAuth.identityId,
|
||||||
stsEndpoint: identityAwsIamAuth.stsEndpoint,
|
stsEndpoint: identityAwsAuth.stsEndpoint,
|
||||||
allowedPrincipalArns: identityAwsIamAuth.allowedPrincipalArns,
|
allowedPrincipalArns: identityAwsAuth.allowedPrincipalArns,
|
||||||
allowedAccountIds: identityAwsIamAuth.allowedAccountIds,
|
allowedAccountIds: identityAwsAuth.allowedAccountIds,
|
||||||
accessTokenTTL: identityAwsIamAuth.accessTokenTTL,
|
accessTokenTTL: identityAwsAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||||
accessTokenTrustedIps: identityAwsIamAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
accessTokenTrustedIps: identityAwsAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
accessTokenNumUsesLimit: identityAwsIamAuth.accessTokenNumUsesLimit
|
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { identityAwsIamAuth };
|
return { identityAwsAuth };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: "/aws-iam-auth/identities/:identityId",
|
url: "/aws-auth/identities/:identityId",
|
||||||
config: {
|
config: {
|
||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
description: "Retrieve AWS IAM Auth configuration on identity",
|
description: "Retrieve AWS Auth configuration on identity",
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
@@ -240,12 +240,12 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
identityAwsIamAuth: IdentityAwsIamAuthsSchema
|
identityAwsAuth: IdentityAwsAuthsSchema
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const identityAwsIamAuth = await server.services.identityAwsIamAuth.getAwsIamAuth({
|
const identityAwsAuth = await server.services.identityAwsAuth.getAwsAuth({
|
||||||
identityId: req.params.identityId,
|
identityId: req.params.identityId,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -255,15 +255,15 @@ export const registerIdentityAwsIamAuthRouter = async (server: FastifyZodProvide
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityAwsIamAuth.orgId,
|
orgId: identityAwsAuth.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.GET_IDENTITY_AWS_IAM_AUTH,
|
type: EventType.GET_IDENTITY_AWS_AUTH,
|
||||||
metadata: {
|
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 { registerAuthRoutes } from "./auth-router";
|
||||||
import { registerProjectBotRouter } from "./bot-router";
|
import { registerProjectBotRouter } from "./bot-router";
|
||||||
import { registerIdentityAccessTokenRouter } from "./identity-access-token-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 { registerIdentityGcpAuthRouter } from "./identity-gcp-auth-router";
|
||||||
import { registerIdentityRouter } from "./identity-router";
|
import { registerIdentityRouter } from "./identity-router";
|
||||||
import { registerIdentityUaRouter } from "./identity-ua";
|
import { registerIdentityUaRouter } from "./identity-ua";
|
||||||
@@ -30,8 +30,9 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
|||||||
await authRouter.register(registerAuthRoutes);
|
await authRouter.register(registerAuthRoutes);
|
||||||
await authRouter.register(registerIdentityUaRouter);
|
await authRouter.register(registerIdentityUaRouter);
|
||||||
await authRouter.register(registerIdentityGcpAuthRouter);
|
await authRouter.register(registerIdentityGcpAuthRouter);
|
||||||
await authRouter.register(registerIdentityAwsIamAuthRouter);
|
|
||||||
await authRouter.register(registerIdentityAccessTokenRouter);
|
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||||
|
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||||
|
await authRouter.register(registerIdentityAwsAuthRouter);
|
||||||
},
|
},
|
||||||
{ prefix: "/auth" }
|
{ prefix: "/auth" }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
|||||||
)
|
)
|
||||||
.optional()
|
.optional()
|
||||||
.describe(INTEGRATION.CREATE.metadata.secretAWSTag),
|
.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({})
|
.default({})
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -293,6 +293,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
workspaceId: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceId),
|
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),
|
environment: z.string().trim().optional().describe(RAW_SECRETS.GET.environment),
|
||||||
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath),
|
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath),
|
||||||
version: z.coerce.number().optional().describe(RAW_SECRETS.GET.version),
|
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]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const { workspaceSlug } = req.query;
|
||||||
let { secretPath, environment, workspaceId } = req.query;
|
let { secretPath, environment, workspaceId } = req.query;
|
||||||
if (req.auth.actor === ActorType.SERVICE) {
|
if (req.auth.actor === ActorType.SERVICE) {
|
||||||
const scope = ServiceTokenScopes.parse(req.auth.serviceToken.scopes);
|
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({
|
const secret = await server.services.secret.getSecretByNameRaw({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -331,6 +335,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.orgId,
|
||||||
environment,
|
environment,
|
||||||
projectId: workspaceId,
|
projectId: workspaceId,
|
||||||
|
projectSlug: workspaceSlug,
|
||||||
path: secretPath,
|
path: secretPath,
|
||||||
secretName: req.params.secretName,
|
secretName: req.params.secretName,
|
||||||
type: req.query.type,
|
type: req.query.type,
|
||||||
@@ -339,7 +344,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
projectId: req.query.workspaceId,
|
projectId: secret.workspace,
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.GET_SECRET,
|
type: EventType.GET_SECRET,
|
||||||
@@ -358,7 +363,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
|||||||
distinctId: getTelemetryDistinctId(req),
|
distinctId: getTelemetryDistinctId(req),
|
||||||
properties: {
|
properties: {
|
||||||
numberOfSecrets: 1,
|
numberOfSecrets: 1,
|
||||||
workspaceId,
|
workspaceId: secret.workspace,
|
||||||
environment,
|
environment,
|
||||||
secretPath: req.query.secretPath,
|
secretPath: req.query.secretPath,
|
||||||
channel: getUserAgentType(req.headers["user-agent"]),
|
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;
|
||||||
|
};
|
||||||
+56
-61
@@ -16,48 +16,43 @@ import { TIdentityDALFactory } from "../identity/identity-dal";
|
|||||||
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
|
import { TIdentityOrgDALFactory } from "../identity/identity-org-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TIdentityAwsIamAuthDALFactory } from "./identity-aws-iam-auth-dal";
|
import { TIdentityAwsAuthDALFactory } from "./identity-aws-auth-dal";
|
||||||
import { extractPrincipalArn } from "./identity-aws-iam-auth-fns";
|
import { extractPrincipalArn } from "./identity-aws-auth-fns";
|
||||||
import {
|
import {
|
||||||
TAttachAWSIAMAuthDTO,
|
TAttachAwsAuthDTO,
|
||||||
TAWSGetCallerIdentityHeaders,
|
TAwsGetCallerIdentityHeaders,
|
||||||
TGetAWSIAMAuthDTO,
|
TGetAwsAuthDTO,
|
||||||
TGetCallerIdentityResponse,
|
TGetCallerIdentityResponse,
|
||||||
TLoginAWSIAMAuthDTO,
|
TLoginAwsAuthDTO,
|
||||||
TUpdateAWSIAMAuthDTO
|
TUpdateAwsAuthDTO
|
||||||
} from "./identity-aws-iam-auth-types";
|
} from "./identity-aws-auth-types";
|
||||||
|
|
||||||
type TIdentityAwsIamAuthServiceFactoryDep = {
|
type TIdentityAwsAuthServiceFactoryDep = {
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create">;
|
||||||
identityAwsIamAuthDAL: Pick<TIdentityAwsIamAuthDALFactory, "findOne" | "transaction" | "create" | "updateById">;
|
identityAwsAuthDAL: Pick<TIdentityAwsAuthDALFactory, "findOne" | "transaction" | "create" | "updateById">;
|
||||||
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
identityOrgMembershipDAL: Pick<TIdentityOrgDALFactory, "findOne">;
|
||||||
identityDAL: Pick<TIdentityDALFactory, "updateById">;
|
identityDAL: Pick<TIdentityDALFactory, "updateById">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityAwsIamAuthServiceFactory = ReturnType<typeof identityAwsIamAuthServiceFactory>;
|
export type TIdentityAwsAuthServiceFactory = ReturnType<typeof identityAwsAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityAwsIamAuthServiceFactory = ({
|
export const identityAwsAuthServiceFactory = ({
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityAwsIamAuthDAL,
|
identityAwsAuthDAL,
|
||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
identityDAL,
|
identityDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
permissionService
|
permissionService
|
||||||
}: TIdentityAwsIamAuthServiceFactoryDep) => {
|
}: TIdentityAwsAuthServiceFactoryDep) => {
|
||||||
const login = async ({
|
const login = async ({ identityId, iamHttpRequestMethod, iamRequestBody, iamRequestHeaders }: TLoginAwsAuthDTO) => {
|
||||||
identityId,
|
const identityAwsAuth = await identityAwsAuthDAL.findOne({ identityId });
|
||||||
iamHttpRequestMethod,
|
if (!identityAwsAuth) throw new UnauthorizedError();
|
||||||
iamRequestBody,
|
|
||||||
iamRequestHeaders
|
|
||||||
}: TLoginAWSIAMAuthDTO) => {
|
|
||||||
const identityAwsIamAuth = await identityAwsIamAuthDAL.findOne({ identityId });
|
|
||||||
if (!identityAwsIamAuth) 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 body: string = Buffer.from(iamRequestBody, "base64").toString();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -68,15 +63,15 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
}: { data: TGetCallerIdentityResponse } = await axios({
|
}: { data: TGetCallerIdentityResponse } = await axios({
|
||||||
method: iamHttpRequestMethod,
|
method: iamHttpRequestMethod,
|
||||||
url: identityAwsIamAuth.stsEndpoint,
|
url: identityAwsAuth.stsEndpoint,
|
||||||
headers,
|
headers,
|
||||||
data: body
|
data: body
|
||||||
});
|
});
|
||||||
|
|
||||||
if (identityAwsIamAuth.allowedAccountIds) {
|
if (identityAwsAuth.allowedAccountIds) {
|
||||||
// validate if Account is in the list of allowed Account IDs
|
// validate if Account is in the list of allowed Account IDs
|
||||||
|
|
||||||
const isAccountAllowed = identityAwsIamAuth.allowedAccountIds
|
const isAccountAllowed = identityAwsAuth.allowedAccountIds
|
||||||
.split(",")
|
.split(",")
|
||||||
.map((accountId) => accountId.trim())
|
.map((accountId) => accountId.trim())
|
||||||
.some((accountId) => accountId === Account);
|
.some((accountId) => accountId === Account);
|
||||||
@@ -84,10 +79,10 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
if (!isAccountAllowed) throw new UnauthorizedError();
|
if (!isAccountAllowed) throw new UnauthorizedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identityAwsIamAuth.allowedPrincipalArns) {
|
if (identityAwsAuth.allowedPrincipalArns) {
|
||||||
// validate if Arn is in the list of allowed Principal ARNs
|
// validate if Arn is in the list of allowed Principal ARNs
|
||||||
|
|
||||||
const isArnAllowed = identityAwsIamAuth.allowedPrincipalArns
|
const isArnAllowed = identityAwsAuth.allowedPrincipalArns
|
||||||
.split(",")
|
.split(",")
|
||||||
.map((principalArn) => principalArn.trim())
|
.map((principalArn) => principalArn.trim())
|
||||||
.some((principalArn) => {
|
.some((principalArn) => {
|
||||||
@@ -100,15 +95,15 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
if (!isArnAllowed) throw new UnauthorizedError();
|
if (!isArnAllowed) throw new UnauthorizedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityAwsIamAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityAwsAuthDAL.transaction(async (tx) => {
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
{
|
{
|
||||||
identityId: identityAwsIamAuth.identityId,
|
identityId: identityAwsAuth.identityId,
|
||||||
isAccessTokenRevoked: false,
|
isAccessTokenRevoked: false,
|
||||||
accessTokenTTL: identityAwsIamAuth.accessTokenTTL,
|
accessTokenTTL: identityAwsAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityAwsIamAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityAwsAuth.accessTokenMaxTTL,
|
||||||
accessTokenNumUses: 0,
|
accessTokenNumUses: 0,
|
||||||
accessTokenNumUsesLimit: identityAwsIamAuth.accessTokenNumUsesLimit
|
accessTokenNumUsesLimit: identityAwsAuth.accessTokenNumUsesLimit
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -118,7 +113,7 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const accessToken = jwt.sign(
|
const accessToken = jwt.sign(
|
||||||
{
|
{
|
||||||
identityId: identityAwsIamAuth.identityId,
|
identityId: identityAwsAuth.identityId,
|
||||||
identityAccessTokenId: identityAccessToken.id,
|
identityAccessTokenId: identityAccessToken.id,
|
||||||
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
authTokenType: AuthTokenType.IDENTITY_ACCESS_TOKEN
|
||||||
} as TIdentityAccessTokenJwtPayload,
|
} 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,
|
identityId,
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
allowedPrincipalArns,
|
allowedPrincipalArns,
|
||||||
@@ -147,12 +142,12 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TAttachAWSIAMAuthDTO) => {
|
}: TAttachAwsAuthDTO) => {
|
||||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
||||||
if (identityMembershipOrg.identity.authMethod)
|
if (identityMembershipOrg.identity.authMethod)
|
||||||
throw new BadRequestError({
|
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) {
|
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
||||||
@@ -186,10 +181,11 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||||
});
|
});
|
||||||
|
|
||||||
const identityAwsIamAuth = await identityAwsIamAuthDAL.transaction(async (tx) => {
|
const identityAwsAuth = await identityAwsAuthDAL.transaction(async (tx) => {
|
||||||
const doc = await identityAwsIamAuthDAL.create(
|
const doc = await identityAwsAuthDAL.create(
|
||||||
{
|
{
|
||||||
identityId: identityMembershipOrg.identityId,
|
identityId: identityMembershipOrg.identityId,
|
||||||
|
type: "iam",
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
allowedPrincipalArns,
|
allowedPrincipalArns,
|
||||||
allowedAccountIds,
|
allowedAccountIds,
|
||||||
@@ -203,16 +199,16 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
await identityDAL.updateById(
|
await identityDAL.updateById(
|
||||||
identityMembershipOrg.identityId,
|
identityMembershipOrg.identityId,
|
||||||
{
|
{
|
||||||
authMethod: IdentityAuthMethod.AWS_IAM_AUTH
|
authMethod: IdentityAuthMethod.AWS_AUTH
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
return doc;
|
return doc;
|
||||||
});
|
});
|
||||||
return { ...identityAwsIamAuth, orgId: identityMembershipOrg.orgId };
|
return { ...identityAwsAuth, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateAwsIamAuth = async ({
|
const updateAwsAuth = async ({
|
||||||
identityId,
|
identityId,
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
allowedPrincipalArns,
|
allowedPrincipalArns,
|
||||||
@@ -225,20 +221,19 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actor,
|
actor,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TUpdateAWSIAMAuthDTO) => {
|
}: TUpdateAwsAuthDTO) => {
|
||||||
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
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({
|
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 (
|
if (
|
||||||
(accessTokenMaxTTL || identityAwsIamAuth.accessTokenMaxTTL) > 0 &&
|
(accessTokenMaxTTL || identityAwsAuth.accessTokenMaxTTL) > 0 &&
|
||||||
(accessTokenTTL || identityAwsIamAuth.accessTokenMaxTTL) >
|
(accessTokenTTL || identityAwsAuth.accessTokenMaxTTL) > (accessTokenMaxTTL || identityAwsAuth.accessTokenMaxTTL)
|
||||||
(accessTokenMaxTTL || identityAwsIamAuth.accessTokenMaxTTL)
|
|
||||||
) {
|
) {
|
||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
@@ -270,7 +265,7 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatedAwsIamAuth = await identityAwsIamAuthDAL.updateById(identityAwsIamAuth.id, {
|
const updatedAwsAuth = await identityAwsAuthDAL.updateById(identityAwsAuth.id, {
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
allowedPrincipalArns,
|
allowedPrincipalArns,
|
||||||
allowedAccountIds,
|
allowedAccountIds,
|
||||||
@@ -282,18 +277,18 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
: undefined
|
: 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 });
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
|
||||||
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
|
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({
|
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(
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
actor,
|
actor,
|
||||||
@@ -303,13 +298,13 @@ export const identityAwsIamAuthServiceFactory = ({
|
|||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
|
||||||
return { ...awsIamIdentityAuth, orgId: identityMembershipOrg.orgId };
|
return { ...awsIdentityAuth, orgId: identityMembershipOrg.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
login,
|
login,
|
||||||
attachAwsIamAuth,
|
attachAwsAuth,
|
||||||
updateAwsIamAuth,
|
updateAwsAuth,
|
||||||
getAwsIamAuth
|
getAwsAuth
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
+5
-5
@@ -1,13 +1,13 @@
|
|||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export type TLoginAWSIAMAuthDTO = {
|
export type TLoginAwsAuthDTO = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
iamHttpRequestMethod: string;
|
iamHttpRequestMethod: string;
|
||||||
iamRequestBody: string;
|
iamRequestBody: string;
|
||||||
iamRequestHeaders: string;
|
iamRequestHeaders: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAttachAWSIAMAuthDTO = {
|
export type TAttachAwsAuthDTO = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint: string;
|
stsEndpoint: string;
|
||||||
allowedPrincipalArns: string;
|
allowedPrincipalArns: string;
|
||||||
@@ -18,7 +18,7 @@ export type TAttachAWSIAMAuthDTO = {
|
|||||||
accessTokenTrustedIps: { ipAddress: string }[];
|
accessTokenTrustedIps: { ipAddress: string }[];
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TUpdateAWSIAMAuthDTO = {
|
export type TUpdateAwsAuthDTO = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint?: string;
|
stsEndpoint?: string;
|
||||||
allowedPrincipalArns?: string;
|
allowedPrincipalArns?: string;
|
||||||
@@ -29,11 +29,11 @@ export type TUpdateAWSIAMAuthDTO = {
|
|||||||
accessTokenTrustedIps?: { ipAddress: string }[];
|
accessTokenTrustedIps?: { ipAddress: string }[];
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TGetAWSIAMAuthDTO = {
|
export type TGetAwsAuthDTO = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TAWSGetCallerIdentityHeaders = {
|
export type TAwsGetCallerIdentityHeaders = {
|
||||||
"Content-Type": string;
|
"Content-Type": string;
|
||||||
Host: string;
|
Host: string;
|
||||||
"X-Amz-Date": 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) => {
|
}: TIdentityUaServiceFactoryDep) => {
|
||||||
const login = async (clientId: string, clientSecret: string, ip: string) => {
|
const login = async (clientId: string, clientSecret: string, ip: string) => {
|
||||||
const identityUa = await identityUaDAL.findOne({ clientId });
|
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 });
|
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId: identityUa.identityId });
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ export const identityUaServiceFactory = ({
|
|||||||
const validClientSecretInfo = clientSecrtInfo.find(({ clientSecretHash }) =>
|
const validClientSecretInfo = clientSecrtInfo.find(({ clientSecretHash }) =>
|
||||||
bcrypt.compareSync(clientSecret, clientSecretHash)
|
bcrypt.compareSync(clientSecret, clientSecretHash)
|
||||||
);
|
);
|
||||||
if (!validClientSecretInfo) throw new UnauthorizedError();
|
if (!validClientSecretInfo) throw new UnauthorizedError({ message: "Invalid credentials" });
|
||||||
|
|
||||||
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
|
const { clientSecretTTL, clientSecretNumUses, clientSecretNumUsesLimit } = validClientSecretInfo;
|
||||||
if (Number(clientSecretTTL) > 0) {
|
if (Number(clientSecretTTL) > 0) {
|
||||||
|
|||||||
@@ -517,20 +517,22 @@ const syncSecretsAWSParameterStore = async ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Identify secrets to delete
|
if (!metadata.shouldDisableDelete) {
|
||||||
await Promise.all(
|
// Identify secrets to delete
|
||||||
Object.keys(awsParameterStoreSecretsObj).map(async (key) => {
|
await Promise.all(
|
||||||
if (!(key in secrets)) {
|
Object.keys(awsParameterStoreSecretsObj).map(async (key) => {
|
||||||
// case:
|
if (!(key in secrets)) {
|
||||||
// -> delete secret
|
// case:
|
||||||
await ssm
|
// -> delete secret
|
||||||
.deleteParameter({
|
await ssm
|
||||||
Name: awsParameterStoreSecretsObj[key].Name as string
|
.deleteParameter({
|
||||||
})
|
Name: awsParameterStoreSecretsObj[key].Name as string
|
||||||
.promise();
|
})
|
||||||
}
|
.promise();
|
||||||
})
|
}
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export type TCreateIntegrationDTO = {
|
|||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
kmsKeyId?: string;
|
kmsKeyId?: string;
|
||||||
|
shouldDisableDelete?: boolean;
|
||||||
};
|
};
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
|||||||
@@ -546,6 +546,10 @@ export const orgServiceFactory = ({
|
|||||||
code
|
code
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await userDAL.updateById(user.id, {
|
||||||
|
isEmailVerified: true
|
||||||
|
});
|
||||||
|
|
||||||
if (user.isAccepted) {
|
if (user.isAccepted) {
|
||||||
// this means user has already completed signup process
|
// this means user has already completed signup process
|
||||||
// isAccepted is set true when keys are exchanged
|
// isAccepted is set true when keys are exchanged
|
||||||
|
|||||||
@@ -972,7 +972,8 @@ export const secretServiceFactory = ({
|
|||||||
path,
|
path,
|
||||||
actor,
|
actor,
|
||||||
environment,
|
environment,
|
||||||
projectId,
|
projectId: workspaceId,
|
||||||
|
projectSlug,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
@@ -980,6 +981,8 @@ export const secretServiceFactory = ({
|
|||||||
includeImports,
|
includeImports,
|
||||||
version
|
version
|
||||||
}: TGetASecretRawDTO) => {
|
}: TGetASecretRawDTO) => {
|
||||||
|
const projectId = workspaceId || (await projectDAL.findProjectBySlug(projectSlug as string, actorOrgId)).id;
|
||||||
|
|
||||||
const botKey = await projectBotService.getBotKey(projectId);
|
const botKey = await projectBotService.getBotKey(projectId);
|
||||||
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
|
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";
|
type: "shared" | "personal";
|
||||||
includeImports?: boolean;
|
includeImports?: boolean;
|
||||||
version?: number;
|
version?: number;
|
||||||
} & TProjectPermission;
|
projectSlug?: string;
|
||||||
|
projectId?: string;
|
||||||
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TCreateSecretRawDTO = TProjectPermission & {
|
export type TCreateSecretRawDTO = TProjectPermission & {
|
||||||
secretPath: string;
|
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.
|
- **[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)).
|
- **[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?
|
## How to get started with Infisical?
|
||||||
|
|
||||||
|
|||||||
+40
-14
@@ -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."
|
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
|
## 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.
|
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.
|
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.
|
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>
|
<Note>
|
||||||
We recommend using one of Infisical's clients like SDKs or the Infisical Agent
|
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
|
authentication process including the signed `GetCallerIdentity` query
|
||||||
construction for you.
|
construction for you.
|
||||||
|
|
||||||
Also, note that Infisical needs network-level access to send requests to the AWS STS API
|
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>
|
</Note>
|
||||||
|
|
||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
In the following steps, we explore how to create and use identities for your workloads and applications on AWS to
|
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>
|
<Steps>
|
||||||
<Step title="Creating an identity">
|
<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.
|
- 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.
|
- 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:
|
Here's some more guidance on each field:
|
||||||
|
|
||||||
@@ -71,7 +97,7 @@ access the Infisical API using the AWS IAM authentication method.
|
|||||||

|

|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Accessing the Infisical API with the identity">
|
<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.
|
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).
|
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 identityId = "<your-identity-id>";
|
||||||
|
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${infisicalUrl}/api/v1/auth/aws-iam-auth/login`,
|
`${infisicalUrl}/api/v1/auth/aws-auth/login`,
|
||||||
{
|
{
|
||||||
identityId,
|
identityId,
|
||||||
iamHttpRequestMethod: "POST",
|
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 infisicalUrl = "https://app.infisical.com"; // or your self-hosted Infisical URL
|
||||||
const identityId = "<your-identity-id>";
|
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,
|
identityId,
|
||||||
iamHttpRequestMethod: "POST",
|
iamHttpRequestMethod: "POST",
|
||||||
iamRequestUrl: Buffer.from(iamRequestURL).toString("base64"),
|
iamRequestUrl: Buffer.from(iamRequestURL).toString("base64"),
|
||||||
@@ -239,7 +265,7 @@ access the Infisical API using the AWS IAM authentication method.
|
|||||||
#### Sample request
|
#### Sample request
|
||||||
|
|
||||||
```bash 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' \
|
--header 'Content-Type: application/x-www-form-urlencoded' \
|
||||||
--data-urlencode 'identityId=...' \
|
--data-urlencode 'identityId=...' \
|
||||||
--data-urlencode 'iamHttpRequestMethod=...' \
|
--data-urlencode 'iamHttpRequestMethod=...' \
|
||||||
@@ -263,7 +289,7 @@ access the Infisical API using the AWS IAM authentication method.
|
|||||||
</AccordionGroup>
|
</AccordionGroup>
|
||||||
|
|
||||||
<Tip>
|
<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>
|
</Tip>
|
||||||
|
|
||||||
<Note>
|
<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).
|
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:
|
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.
|
- [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.
|
- [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 IAM Auth](/documentation/platform/identities/gcp-auth): A GCP-native authentication method for IAM service accounts 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
|
## 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.
|
**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
|
## 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,
|
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.
|
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
|
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.
|
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>
|
projectSlug: <project-slug>
|
||||||
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
||||||
secretsPath: "<secrets-path>" # Root is "/"
|
secretsPath: "<secrets-path>" # Root is "/"
|
||||||
|
recursive: true # Fetch all secrets from the specified path and all sub-directories. Default is false.
|
||||||
|
|
||||||
credentialsRef:
|
credentialsRef:
|
||||||
secretName: universal-auth-credentials
|
secretName: universal-auth-credentials
|
||||||
secretNamespace: default
|
secretNamespace: default
|
||||||
@@ -89,6 +91,7 @@ spec:
|
|||||||
secretsScope:
|
secretsScope:
|
||||||
envSlug: <env-slug>
|
envSlug: <env-slug>
|
||||||
secretsPath: <secrets-path> # Root is "/"
|
secretsPath: <secrets-path> # Root is "/"
|
||||||
|
recursive: true # Fetch all secrets from the specified path and all sub-directories. Default is false.
|
||||||
|
|
||||||
managedSecretReference:
|
managedSecretReference:
|
||||||
secretName: managed-secret
|
secretName: managed-secret
|
||||||
|
|||||||
+1
-1
@@ -153,8 +153,8 @@
|
|||||||
"documentation/platform/auth-methods/email-password",
|
"documentation/platform/auth-methods/email-password",
|
||||||
"documentation/platform/token",
|
"documentation/platform/token",
|
||||||
"documentation/platform/identities/universal-auth",
|
"documentation/platform/identities/universal-auth",
|
||||||
"documentation/platform/identities/aws-iam-auth",
|
|
||||||
"documentation/platform/identities/gcp-auth",
|
"documentation/platform/identities/gcp-auth",
|
||||||
|
"documentation/platform/identities/aws-auth",
|
||||||
"documentation/platform/mfa",
|
"documentation/platform/mfa",
|
||||||
{
|
{
|
||||||
"group": "SSO",
|
"group": "SSO",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const SecretPathInput = ({
|
|||||||
const [inputValue, setInputValue] = useState(propValue ?? "");
|
const [inputValue, setInputValue] = useState(propValue ?? "");
|
||||||
const [secretPath, setSecretPath] = useState("/");
|
const [secretPath, setSecretPath] = useState("/");
|
||||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||||
|
const [isInputFocused, setIsInputFocus] = useState(false);
|
||||||
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||||
const debouncedInputValue = useDebounce(inputValue, 200);
|
const debouncedInputValue = useDebounce(inputValue, 200);
|
||||||
|
|
||||||
@@ -55,7 +56,9 @@ export const SecretPathInput = ({
|
|||||||
) {
|
) {
|
||||||
setSecretPath(debouncedInputValue);
|
setSecretPath(debouncedInputValue);
|
||||||
}
|
}
|
||||||
|
}, [debouncedInputValue]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
// filter suggestions based on matching
|
// filter suggestions based on matching
|
||||||
const searchFragment = debouncedInputValue.split("/").pop() || "";
|
const searchFragment = debouncedInputValue.split("/").pop() || "";
|
||||||
const filteredSuggestions = folders
|
const filteredSuggestions = folders
|
||||||
@@ -65,7 +68,7 @@ export const SecretPathInput = ({
|
|||||||
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
||||||
|
|
||||||
setSuggestions(filteredSuggestions);
|
setSuggestions(filteredSuggestions);
|
||||||
}, [debouncedInputValue]);
|
}, [debouncedInputValue, folders]);
|
||||||
|
|
||||||
const handleSuggestionSelect = (selectedIndex: number) => {
|
const handleSuggestionSelect = (selectedIndex: number) => {
|
||||||
if (!suggestions[selectedIndex]) {
|
if (!suggestions[selectedIndex]) {
|
||||||
@@ -75,7 +78,7 @@ export const SecretPathInput = ({
|
|||||||
const validPaths = inputValue.split("/");
|
const validPaths = inputValue.split("/");
|
||||||
validPaths.pop();
|
validPaths.pop();
|
||||||
|
|
||||||
const newValue = `${validPaths.join("/")}/${suggestions[selectedIndex]}`;
|
const newValue = `${validPaths.join("/")}/${suggestions[selectedIndex]}/`;
|
||||||
onChange?.(newValue);
|
onChange?.(newValue);
|
||||||
setInputValue(newValue);
|
setInputValue(newValue);
|
||||||
setSecretPath(newValue);
|
setSecretPath(newValue);
|
||||||
@@ -108,7 +111,7 @@ export const SecretPathInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover.Root
|
<Popover.Root
|
||||||
open={suggestions.length > 0 && inputValue.length > 1}
|
open={suggestions.length > 0 && isInputFocused}
|
||||||
onOpenChange={() => {
|
onOpenChange={() => {
|
||||||
setHighlightedIndex(-1);
|
setHighlightedIndex(-1);
|
||||||
}}
|
}}
|
||||||
@@ -119,6 +122,8 @@ export const SecretPathInput = ({
|
|||||||
type="text"
|
type="text"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
onFocus={() => setIsInputFocus(true)}
|
||||||
|
onBlur={() => setIsInputFocus(false)}
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className={containerClassName}
|
className={containerClassName}
|
||||||
@@ -150,8 +155,9 @@ export const SecretPathInput = ({
|
|||||||
key={`secret-reference-secret-${i + 1}`}
|
key={`secret-reference-secret-${i + 1}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`${highlightedIndex === i ? "bg-gray-600" : ""
|
className={`${
|
||||||
} 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`}
|
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 gap-2">
|
||||||
<div className="flex items-center text-yellow-700">
|
<div className="flex items-center text-yellow-700">
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ import { IdentityAuthMethod } from "./enums";
|
|||||||
export const identityAuthToNameMap: { [I in IdentityAuthMethod]: string } = {
|
export const identityAuthToNameMap: { [I in IdentityAuthMethod]: string } = {
|
||||||
[IdentityAuthMethod.UNIVERSAL_AUTH]: "Universal Auth",
|
[IdentityAuthMethod.UNIVERSAL_AUTH]: "Universal Auth",
|
||||||
[IdentityAuthMethod.GCP_AUTH]: "GCP 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 {
|
export enum IdentityAuthMethod {
|
||||||
UNIVERSAL_AUTH = "universal-auth",
|
UNIVERSAL_AUTH = "universal-auth",
|
||||||
GCP_AUTH = "gcp-auth",
|
GCP_AUTH = "gcp-auth",
|
||||||
AWS_IAM_AUTH = "aws-iam-auth"
|
AWS_AUTH = "aws-auth"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export { identityAuthToNameMap } from "./constants";
|
export { identityAuthToNameMap } from "./constants";
|
||||||
export { IdentityAuthMethod } from "./enums";
|
export { IdentityAuthMethod } from "./enums";
|
||||||
export {
|
export {
|
||||||
useAddIdentityAwsIamAuth,
|
useAddIdentityAwsAuth,
|
||||||
useAddIdentityGcpAuth,
|
useAddIdentityGcpAuth,
|
||||||
useAddIdentityUniversalAuth,
|
useAddIdentityUniversalAuth,
|
||||||
useCreateIdentity,
|
useCreateIdentity,
|
||||||
@@ -9,12 +9,11 @@ export {
|
|||||||
useDeleteIdentity,
|
useDeleteIdentity,
|
||||||
useRevokeIdentityUniversalAuthClientSecret,
|
useRevokeIdentityUniversalAuthClientSecret,
|
||||||
useUpdateIdentity,
|
useUpdateIdentity,
|
||||||
useUpdateIdentityAwsIamAuth,
|
useUpdateIdentityAwsAuth,
|
||||||
useUpdateIdentityGcpAuth,
|
useUpdateIdentityGcpAuth,
|
||||||
useUpdateIdentityUniversalAuth
|
useUpdateIdentityUniversalAuth} from "./mutations";
|
||||||
} from "./mutations";
|
|
||||||
export {
|
export {
|
||||||
useGetIdentityAwsIamAuth,
|
useGetIdentityAwsAuth,
|
||||||
useGetIdentityGcpAuth,
|
useGetIdentityGcpAuth,
|
||||||
useGetIdentityUniversalAuth,
|
useGetIdentityUniversalAuth,
|
||||||
useGetIdentityUniversalAuthClientSecrets
|
useGetIdentityUniversalAuthClientSecrets
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { apiRequest } from "@app/config/request";
|
|||||||
import { organizationKeys } from "../organization/queries";
|
import { organizationKeys } from "../organization/queries";
|
||||||
import { identitiesKeys } from "./queries";
|
import { identitiesKeys } from "./queries";
|
||||||
import {
|
import {
|
||||||
AddIdentityAwsIamAuthDTO,
|
AddIdentityAwsAuthDTO,
|
||||||
AddIdentityGcpAuthDTO,
|
AddIdentityGcpAuthDTO,
|
||||||
AddIdentityUniversalAuthDTO,
|
AddIdentityUniversalAuthDTO,
|
||||||
ClientSecretData,
|
ClientSecretData,
|
||||||
@@ -15,10 +15,10 @@ import {
|
|||||||
DeleteIdentityDTO,
|
DeleteIdentityDTO,
|
||||||
DeleteIdentityUniversalAuthClientSecretDTO,
|
DeleteIdentityUniversalAuthClientSecretDTO,
|
||||||
Identity,
|
Identity,
|
||||||
IdentityAwsIamAuth,
|
IdentityAwsAuth,
|
||||||
IdentityGcpAuth,
|
IdentityGcpAuth,
|
||||||
IdentityUniversalAuth,
|
IdentityUniversalAuth,
|
||||||
UpdateIdentityAwsIamAuthDTO,
|
UpdateIdentityAwsAuthDTO,
|
||||||
UpdateIdentityDTO,
|
UpdateIdentityDTO,
|
||||||
UpdateIdentityGcpAuthDTO,
|
UpdateIdentityGcpAuthDTO,
|
||||||
UpdateIdentityUniversalAuthDTO
|
UpdateIdentityUniversalAuthDTO
|
||||||
@@ -256,9 +256,9 @@ export const useUpdateIdentityGcpAuth = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useAddIdentityAwsIamAuth = () => {
|
export const useAddIdentityAwsAuth = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
return useMutation<IdentityAwsIamAuth, {}, AddIdentityAwsIamAuthDTO>({
|
return useMutation<IdentityAwsAuth, {}, AddIdentityAwsAuthDTO>({
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
identityId,
|
identityId,
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
@@ -270,9 +270,9 @@ export const useAddIdentityAwsIamAuth = () => {
|
|||||||
accessTokenTrustedIps
|
accessTokenTrustedIps
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
data: { identityAwsIamAuth }
|
data: { identityAwsAuth }
|
||||||
} = await apiRequest.post<{ identityAwsIamAuth: IdentityAwsIamAuth }>(
|
} = await apiRequest.post<{ identityAwsAuth: IdentityAwsAuth }>(
|
||||||
`/api/v1/auth/aws-iam-auth/identities/${identityId}`,
|
`/api/v1/auth/aws-auth/identities/${identityId}`,
|
||||||
{
|
{
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
allowedPrincipalArns,
|
allowedPrincipalArns,
|
||||||
@@ -284,7 +284,7 @@ export const useAddIdentityAwsIamAuth = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return identityAwsIamAuth;
|
return identityAwsAuth;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { organizationId }) => {
|
onSuccess: (_, { organizationId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||||
@@ -292,9 +292,9 @@ export const useAddIdentityAwsIamAuth = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useUpdateIdentityAwsIamAuth = () => {
|
export const useUpdateIdentityAwsAuth = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
return useMutation<IdentityAwsIamAuth, {}, UpdateIdentityAwsIamAuthDTO>({
|
return useMutation<IdentityAwsAuth, {}, UpdateIdentityAwsAuthDTO>({
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
identityId,
|
identityId,
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
@@ -306,9 +306,9 @@ export const useUpdateIdentityAwsIamAuth = () => {
|
|||||||
accessTokenTrustedIps
|
accessTokenTrustedIps
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
data: { identityAwsIamAuth }
|
data: { identityAwsAuth }
|
||||||
} = await apiRequest.patch<{ identityAwsIamAuth: IdentityAwsIamAuth }>(
|
} = await apiRequest.patch<{ identityAwsAuth: IdentityAwsAuth }>(
|
||||||
`/api/v1/auth/aws-iam-auth/identities/${identityId}`,
|
`/api/v1/auth/aws-auth/identities/${identityId}`,
|
||||||
{
|
{
|
||||||
stsEndpoint,
|
stsEndpoint,
|
||||||
allowedPrincipalArns,
|
allowedPrincipalArns,
|
||||||
@@ -320,7 +320,7 @@ export const useUpdateIdentityAwsIamAuth = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return identityAwsIamAuth;
|
return identityAwsAuth;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { organizationId }) => {
|
onSuccess: (_, { organizationId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||||
|
|||||||
@@ -2,12 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
import {
|
import { ClientSecretData, IdentityAwsAuth, IdentityGcpAuth, IdentityUniversalAuth } from "./types";
|
||||||
ClientSecretData,
|
|
||||||
IdentityAwsIamAuth,
|
|
||||||
IdentityGcpAuth,
|
|
||||||
IdentityUniversalAuth
|
|
||||||
} from "./types";
|
|
||||||
|
|
||||||
export const identitiesKeys = {
|
export const identitiesKeys = {
|
||||||
getIdentityUniversalAuth: (identityId: string) =>
|
getIdentityUniversalAuth: (identityId: string) =>
|
||||||
@@ -15,7 +10,7 @@ export const identitiesKeys = {
|
|||||||
getIdentityUniversalAuthClientSecrets: (identityId: string) =>
|
getIdentityUniversalAuthClientSecrets: (identityId: string) =>
|
||||||
[{ identityId }, "identity-universal-auth-client-secrets"] as const,
|
[{ identityId }, "identity-universal-auth-client-secrets"] as const,
|
||||||
getIdentityGcpAuth: (identityId: string) => [{ identityId }, "identity-gcp-auth"] 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) => {
|
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({
|
return useQuery({
|
||||||
enabled: Boolean(identityId),
|
enabled: Boolean(identityId),
|
||||||
queryKey: identitiesKeys.getIdentityAwsIamAuth(identityId),
|
queryKey: identitiesKeys.getIdentityAwsAuth(identityId),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const {
|
const {
|
||||||
data: { identityAwsIamAuth }
|
data: { identityAwsAuth }
|
||||||
} = await apiRequest.get<{ identityAwsIamAuth: IdentityAwsIamAuth }>(
|
} = await apiRequest.get<{ identityAwsAuth: IdentityAwsAuth }>(
|
||||||
`/api/v1/auth/aws-iam-auth/identities/${identityId}`
|
`/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;
|
identityId: string;
|
||||||
|
type: "iam";
|
||||||
stsEndpoint: string;
|
stsEndpoint: string;
|
||||||
allowedPrincipalArns: string;
|
allowedPrincipalArns: string;
|
||||||
allowedAccountIds: string;
|
allowedAccountIds: string;
|
||||||
@@ -169,7 +170,7 @@ export type IdentityAwsIamAuth = {
|
|||||||
accessTokenTrustedIps: IdentityTrustedIp[];
|
accessTokenTrustedIps: IdentityTrustedIp[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AddIdentityAwsIamAuthDTO = {
|
export type AddIdentityAwsAuthDTO = {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint: string;
|
stsEndpoint: string;
|
||||||
@@ -183,7 +184,7 @@ export type AddIdentityAwsIamAuthDTO = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateIdentityAwsIamAuthDTO = {
|
export type UpdateIdentityAwsAuthDTO = {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint?: string;
|
stsEndpoint?: string;
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export const useCreateIntegration = () => {
|
|||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
kmsKeyId?: string;
|
kmsKeyId?: string;
|
||||||
|
shouldDisableDelete?: boolean;
|
||||||
};
|
};
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export const useGetFoldersByEnv = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return [...names];
|
return [...names];
|
||||||
}, [(folders || []).map((folder) => folder.data)]);
|
}, [...(folders || []).map((folder) => folder.data)]);
|
||||||
|
|
||||||
const isFolderPresentInEnv = useCallback(
|
const isFolderPresentInEnv = useCallback(
|
||||||
(name: string, env: string) => {
|
(name: string, env: string) => {
|
||||||
@@ -91,7 +91,7 @@ export const useGetFoldersByEnv = ({
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
[(folders || []).map((folder) => folder.data)]
|
[...(folders || []).map((folder) => folder.data)]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getFolderByNameAndEnv = useCallback(
|
const getFolderByNameAndEnv = useCallback(
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
|||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [shouldTag, setShouldTag] = useState(false);
|
const [shouldTag, setShouldTag] = useState(false);
|
||||||
|
const [shouldDisableDelete, setShouldDisableDelete] = useState(false);
|
||||||
const [tagKey, setTagKey] = useState("");
|
const [tagKey, setTagKey] = useState("");
|
||||||
const [tagValue, setTagValue] = useState("");
|
const [tagValue, setTagValue] = useState("");
|
||||||
const [kmsKeyId, setKmsKeyId] = 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 }}
|
exit={{ opacity: 0, translateX: 30 }}
|
||||||
>
|
>
|
||||||
<div className="mt-2 ml-1">
|
<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
|
<Switch
|
||||||
id="tag-aws"
|
id="tag-aws"
|
||||||
onCheckedChange={() => setShouldTag(!shouldTag)}
|
onCheckedChange={() => setShouldTag(!shouldTag)}
|
||||||
|
|||||||
+5
-5
@@ -14,7 +14,7 @@ import {
|
|||||||
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { IdentityAwsIamAuthForm } from "./IdentityAwsIamAuthForm";
|
import { IdentityAwsAuthForm } from "./IdentityAwsAuthForm";
|
||||||
import { IdentityGcpAuthForm } from "./IdentityGcpAuthForm";
|
import { IdentityGcpAuthForm } from "./IdentityGcpAuthForm";
|
||||||
import { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
import { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
||||||
|
|
||||||
@@ -29,8 +29,8 @@ type Props = {
|
|||||||
|
|
||||||
const identityAuthMethods = [
|
const identityAuthMethods = [
|
||||||
{ label: "Universal Auth", value: IdentityAuthMethod.UNIVERSAL_AUTH },
|
{ 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
|
const schema = yup
|
||||||
@@ -68,9 +68,9 @@ export const IdentityAuthMethodModal = ({ popUp, handlePopUpOpen, handlePopUpTog
|
|||||||
|
|
||||||
const renderIdentityAuthForm = () => {
|
const renderIdentityAuthForm = () => {
|
||||||
switch (identityAuthMethodData?.authMethod ?? authMethod) {
|
switch (identityAuthMethodData?.authMethod ?? authMethod) {
|
||||||
case IdentityAuthMethod.AWS_IAM_AUTH: {
|
case IdentityAuthMethod.AWS_AUTH: {
|
||||||
return (
|
return (
|
||||||
<IdentityAwsIamAuthForm
|
<IdentityAwsAuthForm
|
||||||
handlePopUpOpen={handlePopUpOpen}
|
handlePopUpOpen={handlePopUpOpen}
|
||||||
handlePopUpToggle={handlePopUpToggle}
|
handlePopUpToggle={handlePopUpToggle}
|
||||||
identityAuthMethodData={identityAuthMethodData}
|
identityAuthMethodData={identityAuthMethodData}
|
||||||
|
|||||||
+7
-7
@@ -9,9 +9,9 @@ import { createNotification } from "@app/components/notifications";
|
|||||||
import { Button, FormControl, IconButton, Input } from "@app/components/v2";
|
import { Button, FormControl, IconButton, Input } from "@app/components/v2";
|
||||||
import { useOrganization, useSubscription } from "@app/context";
|
import { useOrganization, useSubscription } from "@app/context";
|
||||||
import {
|
import {
|
||||||
useAddIdentityAwsIamAuth,
|
useAddIdentityAwsAuth,
|
||||||
useGetIdentityAwsIamAuth,
|
useGetIdentityAwsAuth,
|
||||||
useUpdateIdentityAwsIamAuth
|
useUpdateIdentityAwsAuth
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
import { IdentityAuthMethod } from "@app/hooks/api/identities";
|
||||||
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
|
import { IdentityTrustedIp } from "@app/hooks/api/identities/types";
|
||||||
@@ -52,7 +52,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IdentityAwsIamAuthForm = ({
|
export const IdentityAwsAuthForm = ({
|
||||||
handlePopUpOpen,
|
handlePopUpOpen,
|
||||||
handlePopUpToggle,
|
handlePopUpToggle,
|
||||||
identityAuthMethodData
|
identityAuthMethodData
|
||||||
@@ -61,10 +61,10 @@ export const IdentityAwsIamAuthForm = ({
|
|||||||
const orgId = currentOrg?.id || "";
|
const orgId = currentOrg?.id || "";
|
||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { mutateAsync: addMutateAsync } = useAddIdentityAwsIamAuth();
|
const { mutateAsync: addMutateAsync } = useAddIdentityAwsAuth();
|
||||||
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsIamAuth();
|
const { mutateAsync: updateMutateAsync } = useUpdateIdentityAwsAuth();
|
||||||
|
|
||||||
const { data } = useGetIdentityAwsIamAuth(identityAuthMethodData?.identityId ?? "");
|
const { data } = useGetIdentityAwsAuth(identityAuthMethodData?.identityId ?? "");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@@ -13,7 +13,7 @@ type: application
|
|||||||
# This is the chart version. This version number should be incremented each time you make changes
|
# 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.
|
# to the chart and its templates, including the app version.
|
||||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
# 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
|
# 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
|
# 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.
|
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ spec:
|
|||||||
properties:
|
properties:
|
||||||
envSlug:
|
envSlug:
|
||||||
type: string
|
type: string
|
||||||
|
recursive:
|
||||||
|
type: boolean
|
||||||
secretsPath:
|
secretsPath:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
@@ -111,6 +113,8 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
projectSlug:
|
projectSlug:
|
||||||
type: string
|
type: string
|
||||||
|
recursive:
|
||||||
|
type: boolean
|
||||||
secretsPath:
|
secretsPath:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ controllerManager:
|
|||||||
- ALL
|
- ALL
|
||||||
image:
|
image:
|
||||||
repository: infisical/kubernetes-operator
|
repository: infisical/kubernetes-operator
|
||||||
tag: v0.5.0 # fixed to prevent accidental upgrade
|
tag: v0.5.1 # fixed to prevent accidental upgrade
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
cpu: 500m
|
cpu: 500m
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ type SecretScopeInWorkspace struct {
|
|||||||
SecretsPath string `json:"secretsPath"`
|
SecretsPath string `json:"secretsPath"`
|
||||||
// +kubebuilder:validation:Required
|
// +kubebuilder:validation:Required
|
||||||
EnvSlug string `json:"envSlug"`
|
EnvSlug string `json:"envSlug"`
|
||||||
|
// +kubebuilder:validation:Optional
|
||||||
|
Recursive bool `json:"recursive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MachineIdentityScopeInWorkspace struct {
|
type MachineIdentityScopeInWorkspace struct {
|
||||||
@@ -47,6 +49,8 @@ type MachineIdentityScopeInWorkspace struct {
|
|||||||
EnvSlug string `json:"envSlug"`
|
EnvSlug string `json:"envSlug"`
|
||||||
// +kubebuilder:validation:Required
|
// +kubebuilder:validation:Required
|
||||||
ProjectSlug string `json:"projectSlug"`
|
ProjectSlug string `json:"projectSlug"`
|
||||||
|
// +kubebuilder:validation:Optional
|
||||||
|
Recursive bool `json:"recursive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type KubeSecretReference struct {
|
type KubeSecretReference struct {
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ spec:
|
|||||||
properties:
|
properties:
|
||||||
envSlug:
|
envSlug:
|
||||||
type: string
|
type: string
|
||||||
|
recursive:
|
||||||
|
type: boolean
|
||||||
secretsPath:
|
secretsPath:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
@@ -111,6 +113,8 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
projectSlug:
|
projectSlug:
|
||||||
type: string
|
type: string
|
||||||
|
recursive:
|
||||||
|
type: boolean
|
||||||
secretsPath:
|
secretsPath:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ spec:
|
|||||||
secretsScope:
|
secretsScope:
|
||||||
envSlug: <env-slug>
|
envSlug: <env-slug>
|
||||||
secretsPath: <secrets-path> # Root is "/"
|
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:
|
universalAuth:
|
||||||
secretsScope:
|
secretsScope:
|
||||||
projectSlug: <project-slug>
|
projectSlug: <project-slug>
|
||||||
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
envSlug: <env-slug> # "dev", "staging", "prod", etc..
|
||||||
secretsPath: "<secrets-path>" # Root is "/"
|
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:
|
credentialsRef:
|
||||||
secretName: universal-auth-credentials
|
secretName: universal-auth-credentials
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ func (r *InfisicalSecretReconciler) ReconcileInfisicalSecret(ctx context.Context
|
|||||||
} else if infisicalMachineIdentityCreds.ClientId != "" && infisicalMachineIdentityCreds.ClientSecret != "" {
|
} else if infisicalMachineIdentityCreds.ClientId != "" && infisicalMachineIdentityCreds.ClientSecret != "" {
|
||||||
authStrategy = AuthStrategy.UNIVERSAL_MACHINE_IDENTITY
|
authStrategy = AuthStrategy.UNIVERSAL_MACHINE_IDENTITY
|
||||||
} else {
|
} 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)
|
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)
|
} else if authStrategy == AuthStrategy.SERVICE_TOKEN { // Service Tokens (deprecated)
|
||||||
envSlug := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.EnvSlug
|
envSlug := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.EnvSlug
|
||||||
secretsPath := infisicalSecret.Spec.Authentication.ServiceToken.SecretsScope.SecretsPath
|
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 {
|
if err != nil {
|
||||||
return fmt.Errorf("\nfailed to get secrets because [err=%v]", err)
|
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)
|
httpRequest.SetQueryParam("secretPath", request.SecretPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if request.Recursive {
|
||||||
|
httpRequest.SetQueryParam("recursive", "true")
|
||||||
|
}
|
||||||
|
|
||||||
response, err := httpRequest.Get(fmt.Sprintf("%v/v3/secrets", API_HOST_URL))
|
response, err := httpRequest.Get(fmt.Sprintf("%v/v3/secrets", API_HOST_URL))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -148,19 +152,23 @@ func CallUniversalMachineIdentityRefreshAccessToken(request MachineIdentityUnive
|
|||||||
func CallGetDecryptedSecretsV3(httpClient *resty.Client, request GetDecryptedSecretsV3Request) (GetDecryptedSecretsV3Response, error) {
|
func CallGetDecryptedSecretsV3(httpClient *resty.Client, request GetDecryptedSecretsV3Request) (GetDecryptedSecretsV3Response, error) {
|
||||||
var decryptedSecretsResponse GetDecryptedSecretsV3Response
|
var decryptedSecretsResponse GetDecryptedSecretsV3Response
|
||||||
|
|
||||||
response, err := httpClient.
|
req := httpClient.
|
||||||
R().
|
R().
|
||||||
SetResult(&decryptedSecretsResponse).
|
SetResult(&decryptedSecretsResponse).
|
||||||
SetHeader("User-Agent", USER_AGENT_NAME).
|
SetHeader("User-Agent", USER_AGENT_NAME).
|
||||||
SetQueryParam("secretPath", request.SecretPath).
|
SetQueryParam("secretPath", request.SecretPath).
|
||||||
SetQueryParam("workspaceSlug", request.ProjectSlug).
|
SetQueryParam("workspaceSlug", request.ProjectSlug).
|
||||||
SetQueryParam("environment", request.Environment).
|
SetQueryParam("environment", request.Environment)
|
||||||
Get(fmt.Sprintf("%v/v3/secrets/raw", API_HOST_URL))
|
|
||||||
|
if request.Recursive {
|
||||||
|
req.SetQueryParam("recursive", "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := req.Get(fmt.Sprintf("%v/v3/secrets/raw", API_HOST_URL))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GetDecryptedSecretsV3Response{}, fmt.Errorf("CallGetDecryptedSecretsV3: Unable to complete api request [err=%s]", err)
|
return GetDecryptedSecretsV3Response{}, fmt.Errorf("CallGetDecryptedSecretsV3: Unable to complete api request [err=%s]", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.IsError() {
|
if response.IsError() {
|
||||||
return GetDecryptedSecretsV3Response{}, fmt.Errorf("CallGetDecryptedSecretsV3: Unsuccessful response: [response=%s]", response)
|
return GetDecryptedSecretsV3Response{}, fmt.Errorf("CallGetDecryptedSecretsV3: Unsuccessful response: [response=%s]", response)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type GetEncryptedWorkspaceKeyResponse struct {
|
|||||||
type GetEncryptedSecretsV3Request struct {
|
type GetEncryptedSecretsV3Request struct {
|
||||||
Environment string `json:"environment"`
|
Environment string `json:"environment"`
|
||||||
WorkspaceId string `json:"workspaceId"`
|
WorkspaceId string `json:"workspaceId"`
|
||||||
|
Recursive bool `json:"recursive"`
|
||||||
SecretPath string `json:"secretPath"`
|
SecretPath string `json:"secretPath"`
|
||||||
IncludeImport bool `json:"include_imports"`
|
IncludeImport bool `json:"include_imports"`
|
||||||
ETag string `json:"etag,omitempty"`
|
ETag string `json:"etag,omitempty"`
|
||||||
@@ -100,6 +101,7 @@ type GetDecryptedSecretsV3Request struct {
|
|||||||
ProjectSlug string `json:"workspaceSlug"`
|
ProjectSlug string `json:"workspaceSlug"`
|
||||||
Environment string `json:"environment"`
|
Environment string `json:"environment"`
|
||||||
SecretPath string `json:"secretPath"`
|
SecretPath string `json:"secretPath"`
|
||||||
|
Recursive bool `json:"recursive"`
|
||||||
ETag string `json:"etag,omitempty"`
|
ETag string `json:"etag,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ func GetPlainTextSecretsViaUniversalAuth(accessToken string, etag string, secret
|
|||||||
secretsResponse, err := api.CallGetDecryptedSecretsV3(httpClient, api.GetDecryptedSecretsV3Request{
|
secretsResponse, err := api.CallGetDecryptedSecretsV3(httpClient, api.GetDecryptedSecretsV3Request{
|
||||||
ProjectSlug: secretScope.ProjectSlug,
|
ProjectSlug: secretScope.ProjectSlug,
|
||||||
Environment: secretScope.EnvSlug,
|
Environment: secretScope.EnvSlug,
|
||||||
|
Recursive: secretScope.Recursive,
|
||||||
SecretPath: secretScope.SecretsPath,
|
SecretPath: secretScope.SecretsPath,
|
||||||
ETag: etag,
|
ETag: etag,
|
||||||
})
|
})
|
||||||
@@ -85,7 +86,7 @@ func GetPlainTextSecretsViaUniversalAuth(accessToken string, etag string, secret
|
|||||||
}, nil
|
}, 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)
|
serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4)
|
||||||
if len(serviceTokenParts) < 4 {
|
if len(serviceTokenParts) < 4 {
|
||||||
return nil, model.RequestUpdateUpdateDetails{}, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
|
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{
|
encryptedSecretsResponse, err := api.CallGetSecretsV3(httpClient, api.GetEncryptedSecretsV3Request{
|
||||||
WorkspaceId: serviceTokenDetails.Workspace,
|
WorkspaceId: serviceTokenDetails.Workspace,
|
||||||
Environment: envSlug,
|
Environment: envSlug,
|
||||||
|
Recursive: recursive,
|
||||||
ETag: etag,
|
ETag: etag,
|
||||||
SecretPath: secretPath,
|
SecretPath: secretPath,
|
||||||
})
|
})
|
||||||
@@ -376,7 +378,7 @@ func ExpandSecrets(secrets []model.SingleEnvironmentVariable, infisicalToken str
|
|||||||
|
|
||||||
if crossRefSec, ok := crossEnvRefSecs[uniqKey]; !ok {
|
if crossRefSec, ok := crossEnvRefSecs[uniqKey]; !ok {
|
||||||
// if not in cross reference cache, fetch it from server
|
// 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 {
|
if err != nil {
|
||||||
fmt.Printf("Could not fetch secrets in environment: %s secret-path: %s", env, secPath)
|
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")
|
// 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 +0,0 @@
|
|||||||
db
|
|
||||||
Generated
-1487
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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-451
@@ -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