mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-28 02:53:22 +00:00
Compare commits
18 Commits
aws-non-de
...
infisical/
Author | SHA1 | Date | |
---|---|---|---|
|
7c77a4f049 | ||
|
9dfb587032 | ||
|
3952ad9a2e | ||
|
9c15cb407d | ||
|
cb17efa10b | ||
|
4adc2c4927 | ||
|
1a26b34ad8 | ||
|
21c339d27a | ||
|
1da4cf85f8 | ||
|
20f29c752d | ||
|
29ea12f8b1 | ||
|
b4f1cce587 | ||
|
5a92520ca3 | ||
|
42471b22bb | ||
|
1165d11816 | ||
|
15ea96815c | ||
|
86d4d88b58 | ||
|
a12ad91e59 |
@@ -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
|
||||||
|
8
backend/package-lock.json
generated
8
backend/package-lock.json
generated
@@ -49,7 +49,7 @@
|
|||||||
"libsodium-wrappers": "^0.7.13",
|
"libsodium-wrappers": "^0.7.13",
|
||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"ms": "^2.1.3",
|
"ms": "^2.1.3",
|
||||||
"mysql2": "^3.9.4",
|
"mysql2": "^3.9.7",
|
||||||
"nanoid": "^5.0.4",
|
"nanoid": "^5.0.4",
|
||||||
"nodemailer": "^6.9.9",
|
"nodemailer": "^6.9.9",
|
||||||
"ora": "^7.0.1",
|
"ora": "^7.0.1",
|
||||||
@@ -10102,9 +10102,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mysql2": {
|
"node_modules/mysql2": {
|
||||||
"version": "3.9.4",
|
"version": "3.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.7.tgz",
|
||||||
"integrity": "sha512-OEESQuwxMza803knC1YSt7NMuc1BrK9j7gZhCSs2WAyxr1vfiI7QLaLOKTh5c9SWGz98qVyQUbK8/WckevNQhg==",
|
"integrity": "sha512-KnJT8vYRcNAZv73uf9zpXqNbvBG7DJrs+1nACsjZP1HMJ1TgXEy8wnNilXAn/5i57JizXKtrUtwDB7HxT9DDpw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"denque": "^2.1.0",
|
"denque": "^2.1.0",
|
||||||
"generate-function": "^2.3.1",
|
"generate-function": "^2.3.1",
|
||||||
|
4
backend/src/@types/fastify.d.ts
vendored
4
backend/src/@types/fastify.d.ts
vendored
@@ -32,7 +32,7 @@ import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-se
|
|||||||
import { TGroupProjectServiceFactory } from "@app/services/group-project/group-project-service";
|
import { 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 { 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";
|
||||||
import { TIntegrationServiceFactory } from "@app/services/integration/integration-service";
|
import { TIntegrationServiceFactory } from "@app/services/integration/integration-service";
|
||||||
@@ -116,7 +116,7 @@ declare module "fastify" {
|
|||||||
identityAccessToken: TIdentityAccessTokenServiceFactory;
|
identityAccessToken: TIdentityAccessTokenServiceFactory;
|
||||||
identityProject: TIdentityProjectServiceFactory;
|
identityProject: TIdentityProjectServiceFactory;
|
||||||
identityUa: TIdentityUaServiceFactory;
|
identityUa: TIdentityUaServiceFactory;
|
||||||
identityAwsIamAuth: TIdentityAwsIamAuthServiceFactory;
|
identityAwsAuth: TIdentityAwsAuthServiceFactory;
|
||||||
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
|
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
|
||||||
accessApprovalRequest: TAccessApprovalRequestServiceFactory;
|
accessApprovalRequest: TAccessApprovalRequestServiceFactory;
|
||||||
secretApprovalPolicy: TSecretApprovalPolicyServiceFactory;
|
secretApprovalPolicy: TSecretApprovalPolicyServiceFactory;
|
||||||
|
14
backend/src/@types/knex.d.ts
vendored
14
backend/src/@types/knex.d.ts
vendored
@@ -59,9 +59,9 @@ import {
|
|||||||
TIdentityAccessTokens,
|
TIdentityAccessTokens,
|
||||||
TIdentityAccessTokensInsert,
|
TIdentityAccessTokensInsert,
|
||||||
TIdentityAccessTokensUpdate,
|
TIdentityAccessTokensUpdate,
|
||||||
TIdentityAwsIamAuths,
|
TIdentityAwsAuths,
|
||||||
TIdentityAwsIamAuthsInsert,
|
TIdentityAwsAuthsInsert,
|
||||||
TIdentityAwsIamAuthsUpdate,
|
TIdentityAwsAuthsUpdate,
|
||||||
TIdentityOrgMemberships,
|
TIdentityOrgMemberships,
|
||||||
TIdentityOrgMembershipsInsert,
|
TIdentityOrgMembershipsInsert,
|
||||||
TIdentityOrgMembershipsUpdate,
|
TIdentityOrgMembershipsUpdate,
|
||||||
@@ -329,10 +329,10 @@ declare module "knex/types/tables" {
|
|||||||
TIdentityUniversalAuthsInsert,
|
TIdentityUniversalAuthsInsert,
|
||||||
TIdentityUniversalAuthsUpdate
|
TIdentityUniversalAuthsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.IdentityAwsIamAuth]: Knex.CompositeTableType<
|
[TableName.IdentityAwsAuth]: Knex.CompositeTableType<
|
||||||
TIdentityAwsIamAuths,
|
TIdentityAwsAuths,
|
||||||
TIdentityAwsIamAuthsInsert,
|
TIdentityAwsAuthsInsert,
|
||||||
TIdentityAwsIamAuthsUpdate
|
TIdentityAwsAuthsUpdate
|
||||||
>;
|
>;
|
||||||
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
[TableName.IdentityUaClientSecret]: Knex.CompositeTableType<
|
||||||
TIdentityUaClientSecrets,
|
TIdentityUaClientSecrets,
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
@@ -11,8 +11,8 @@ export const AccessApprovalPoliciesSchema = z.object({
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
approvals: z.number().default(1),
|
approvals: z.number().default(1),
|
||||||
envId: z.string().uuid(),
|
|
||||||
secretPath: z.string().nullable().optional(),
|
secretPath: z.string().nullable().optional(),
|
||||||
|
envId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date()
|
||||||
});
|
});
|
||||||
|
@@ -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-org-memberships";
|
export * from "./identity-org-memberships";
|
||||||
export * from "./identity-project-additional-privilege";
|
export * from "./identity-project-additional-privilege";
|
||||||
export * from "./identity-project-membership-role";
|
export * from "./identity-project-membership-role";
|
||||||
|
@@ -45,7 +45,7 @@ export enum TableName {
|
|||||||
IdentityAccessToken = "identity_access_tokens",
|
IdentityAccessToken = "identity_access_tokens",
|
||||||
IdentityUniversalAuth = "identity_universal_auths",
|
IdentityUniversalAuth = "identity_universal_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",
|
||||||
@@ -144,5 +144,5 @@ export enum ProjectUpgradeStatus {
|
|||||||
|
|
||||||
export enum IdentityAuthMethod {
|
export enum IdentityAuthMethod {
|
||||||
Univeral = "universal-auth",
|
Univeral = "universal-auth",
|
||||||
AWS_IAM_AUTH = "aws-iam-auth"
|
AWS_AUTH = "aws-auth"
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ export const UsersSchema = z.object({
|
|||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
isGhost: z.boolean().default(false),
|
isGhost: z.boolean().default(false),
|
||||||
username: z.string(),
|
username: z.string(),
|
||||||
isEmailVerified: z.boolean().nullable().optional()
|
isEmailVerified: z.boolean().default(false).nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TUsers = z.infer<typeof UsersSchema>;
|
export type TUsers = z.infer<typeof UsersSchema>;
|
||||||
|
@@ -66,10 +66,10 @@ export enum EventType {
|
|||||||
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
|
CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
|
||||||
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
|
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
|
||||||
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
|
GET_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRETS = "get-identity-universal-auth-client-secret",
|
||||||
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",
|
||||||
@@ -410,17 +410,17 @@ interface RevokeIdentityUniversalAuthClientSecretEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -433,8 +433,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;
|
||||||
@@ -447,8 +447,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;
|
||||||
};
|
};
|
||||||
@@ -708,10 +708,10 @@ export type Event =
|
|||||||
| CreateIdentityUniversalAuthClientSecretEvent
|
| CreateIdentityUniversalAuthClientSecretEvent
|
||||||
| GetIdentityUniversalAuthClientSecretsEvent
|
| GetIdentityUniversalAuthClientSecretsEvent
|
||||||
| RevokeIdentityUniversalAuthClientSecretEvent
|
| RevokeIdentityUniversalAuthClientSecretEvent
|
||||||
| 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.",
|
||||||
|
@@ -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 { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
||||||
import { identityProjectMembershipRoleDALFactory } from "@app/services/identity-project/identity-project-membership-role-dal";
|
import { identityProjectMembershipRoleDALFactory } from "@app/services/identity-project/identity-project-membership-role-dal";
|
||||||
import { identityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
import { identityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
|
||||||
@@ -203,7 +203,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 auditLogDAL = auditLogDALFactory(db);
|
const auditLogDAL = auditLogDALFactory(db);
|
||||||
const auditLogStreamDAL = auditLogStreamDALFactory(db);
|
const auditLogStreamDAL = auditLogStreamDALFactory(db);
|
||||||
@@ -702,9 +702,9 @@ export const registerRoutes = async (
|
|||||||
identityUaDAL,
|
identityUaDAL,
|
||||||
licenseService
|
licenseService
|
||||||
});
|
});
|
||||||
const identityAWSIAMAuthService = identityAwsIamAuthServiceFactory({
|
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityAwsIamAuthDAL,
|
identityAwsAuthDAL,
|
||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
identityDAL,
|
identityDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
@@ -779,7 +779,7 @@ export const registerRoutes = async (
|
|||||||
identityAccessToken: identityAccessTokenService,
|
identityAccessToken: identityAccessTokenService,
|
||||||
identityProject: identityProjectService,
|
identityProject: identityProjectService,
|
||||||
identityUa: identityUaService,
|
identityUa: identityUaService,
|
||||||
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 { registerIdentityRouter } from "./identity-router";
|
import { registerIdentityRouter } from "./identity-router";
|
||||||
import { registerIdentityUaRouter } from "./identity-ua";
|
import { registerIdentityUaRouter } from "./identity-ua";
|
||||||
import { registerIntegrationAuthRouter } from "./integration-auth-router";
|
import { registerIntegrationAuthRouter } from "./integration-auth-router";
|
||||||
@@ -29,7 +29,7 @@ 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(registerIdentityAccessTokenRouter);
|
await authRouter.register(registerIdentityAccessTokenRouter);
|
||||||
await authRouter.register(registerIdentityAwsIamAuthRouter);
|
await authRouter.register(registerIdentityAwsAuthRouter);
|
||||||
},
|
},
|
||||||
{ prefix: "/auth" }
|
{ prefix: "/auth" }
|
||||||
);
|
);
|
||||||
|
@@ -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;
|
||||||
|
};
|
@@ -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
|
||||||
};
|
};
|
||||||
};
|
};
|
@@ -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) {
|
||||||
|
@@ -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?
|
||||||
|
|
||||||
|
@@ -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 using a supported authentication method like [Universal Auth](/documentation/platform/identities/universal-auth) or [AWS IAM Auth](/documentation/platform/identities/aws-iam-auth) to get back a short-lived access token to be used in subsequent requests.
|
Each identity must authenticate using a supported authentication method like [Universal Auth](/documentation/platform/identities/universal-auth) or [AWS Auth](/documentation/platform/identities/aws-auth) to get back a short-lived access token to be used in subsequent requests.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ Key Features:
|
|||||||
A typical workflow for using identities consists of four steps:
|
A typical workflow for using identities consists of four steps:
|
||||||
|
|
||||||
1. Creating the identity with a name and [role](/documentation/platform/role-based-access-controls) in Organization Access Control > Machine Identities.
|
1. Creating the identity with a name and [role](/documentation/platform/role-based-access-controls) in Organization Access Control > Machine Identities.
|
||||||
This step also involves configuring an authentication method for it such as [Universal Auth](/documentation/platform/identities/universal-auth) or [AWS IAM Auth](/documentation/platform/identities/aws-iam-auth).
|
This step also involves configuring an authentication method for it such as [Universal Auth](/documentation/platform/identities/universal-auth) or [AWS Auth](/documentation/platform/identities/aws-auth).
|
||||||
2. Adding the identity to the project(s) you want it to have access to.
|
2. Adding the identity to the project(s) you want it to have access to.
|
||||||
3. Authenticating the identity with the Infisical API based on the configured authentication method on it and receiving a short-lived access token back.
|
3. Authenticating the identity with the Infisical API based on the configured authentication method on it and receiving a short-lived access token back.
|
||||||
4. Authenticating subsequent requests with the Infisical API using the short-lived access token.
|
4. Authenticating subsequent requests with the Infisical API using the short-lived access token.
|
||||||
@@ -38,7 +38,7 @@ 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.
|
||||||
|
|
||||||
## 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 |
@@ -153,7 +153,7 @@
|
|||||||
"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/aws-auth",
|
||||||
"documentation/platform/mfa",
|
"documentation/platform/mfa",
|
||||||
{
|
{
|
||||||
"group": "SSO",
|
"group": "SSO",
|
||||||
|
@@ -2,5 +2,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.AWS_IAM_AUTH]: "AWS IAM Auth"
|
[IdentityAuthMethod.AWS_AUTH]: "AWS Auth"
|
||||||
};
|
};
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
export enum IdentityAuthMethod {
|
export enum IdentityAuthMethod {
|
||||||
UNIVERSAL_AUTH = "universal-auth",
|
UNIVERSAL_AUTH = "universal-auth",
|
||||||
AWS_IAM_AUTH = "aws-iam-auth"
|
AWS_AUTH = "aws-auth"
|
||||||
}
|
}
|
||||||
|
@@ -1,16 +1,18 @@
|
|||||||
export { identityAuthToNameMap } from "./constants";
|
export { identityAuthToNameMap } from "./constants";
|
||||||
export { IdentityAuthMethod } from "./enums";
|
export { IdentityAuthMethod } from "./enums";
|
||||||
export {
|
export {
|
||||||
useAddIdentityAwsIamAuth,
|
useAddIdentityAwsAuth,
|
||||||
useAddIdentityUniversalAuth,
|
useAddIdentityUniversalAuth,
|
||||||
useCreateIdentity,
|
useCreateIdentity,
|
||||||
useCreateIdentityUniversalAuthClientSecret,
|
useCreateIdentityUniversalAuthClientSecret,
|
||||||
useDeleteIdentity,
|
useDeleteIdentity,
|
||||||
useRevokeIdentityUniversalAuthClientSecret,
|
useRevokeIdentityUniversalAuthClientSecret,
|
||||||
useUpdateIdentity,
|
useUpdateIdentity,
|
||||||
useUpdateIdentityAwsIamAuth,
|
useUpdateIdentityAwsAuth,
|
||||||
useUpdateIdentityUniversalAuth} from "./mutations";
|
useUpdateIdentityUniversalAuth
|
||||||
|
} from "./mutations";
|
||||||
export {
|
export {
|
||||||
useGetIdentityAwsIamAuth,
|
useGetIdentityAwsAuth,
|
||||||
useGetIdentityUniversalAuth,
|
useGetIdentityUniversalAuth,
|
||||||
useGetIdentityUniversalAuthClientSecrets} from "./queries";
|
useGetIdentityUniversalAuthClientSecrets
|
||||||
|
} from "./queries";
|
||||||
|
@@ -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,
|
||||||
AddIdentityUniversalAuthDTO,
|
AddIdentityUniversalAuthDTO,
|
||||||
ClientSecretData,
|
ClientSecretData,
|
||||||
CreateIdentityDTO,
|
CreateIdentityDTO,
|
||||||
@@ -14,11 +14,12 @@ import {
|
|||||||
DeleteIdentityDTO,
|
DeleteIdentityDTO,
|
||||||
DeleteIdentityUniversalAuthClientSecretDTO,
|
DeleteIdentityUniversalAuthClientSecretDTO,
|
||||||
Identity,
|
Identity,
|
||||||
IdentityAwsIamAuth,
|
IdentityAwsAuth,
|
||||||
IdentityUniversalAuth,
|
IdentityUniversalAuth,
|
||||||
UpdateIdentityAwsIamAuthDTO,
|
UpdateIdentityAwsAuthDTO,
|
||||||
UpdateIdentityDTO,
|
UpdateIdentityDTO,
|
||||||
UpdateIdentityUniversalAuthDTO} from "./types";
|
UpdateIdentityUniversalAuthDTO
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
export const useCreateIdentity = () => {
|
export const useCreateIdentity = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -172,9 +173,9 @@ export const useRevokeIdentityUniversalAuthClientSecret = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
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,
|
||||||
@@ -186,9 +187,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,
|
||||||
@@ -200,7 +201,7 @@ export const useAddIdentityAwsIamAuth = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return identityAwsIamAuth;
|
return identityAwsAuth;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { organizationId }) => {
|
onSuccess: (_, { organizationId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||||
@@ -208,9 +209,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,
|
||||||
@@ -222,9 +223,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,
|
||||||
@@ -235,7 +236,7 @@ export const useUpdateIdentityAwsIamAuth = () => {
|
|||||||
accessTokenTrustedIps
|
accessTokenTrustedIps
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return identityAwsIamAuth;
|
return identityAwsAuth;
|
||||||
},
|
},
|
||||||
onSuccess: (_, { organizationId }) => {
|
onSuccess: (_, { organizationId }) => {
|
||||||
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
|
||||||
|
@@ -2,14 +2,14 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
import { ClientSecretData, IdentityAwsIamAuth,IdentityUniversalAuth } from "./types";
|
import { ClientSecretData, IdentityAwsAuth, IdentityUniversalAuth } from "./types";
|
||||||
|
|
||||||
export const identitiesKeys = {
|
export const identitiesKeys = {
|
||||||
getIdentityUniversalAuth: (identityId: string) =>
|
getIdentityUniversalAuth: (identityId: string) =>
|
||||||
[{ identityId }, "identity-universal-auth"] as const,
|
[{ identityId }, "identity-universal-auth"] as const,
|
||||||
getIdentityUniversalAuthClientSecrets: (identityId: string) =>
|
getIdentityUniversalAuthClientSecrets: (identityId: string) =>
|
||||||
[{ identityId }, "identity-universal-auth-client-secrets"] as const,
|
[{ identityId }, "identity-universal-auth-client-secrets"] 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) => {
|
||||||
@@ -42,17 +42,17 @@ export const useGetIdentityUniversalAuthClientSecrets = (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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -113,8 +113,9 @@ export type UpdateIdentityUniversalAuthDTO = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type IdentityAwsIamAuth = {
|
export type IdentityAwsAuth = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
|
type: "iam";
|
||||||
stsEndpoint: string;
|
stsEndpoint: string;
|
||||||
allowedPrincipalArns: string;
|
allowedPrincipalArns: string;
|
||||||
allowedAccountIds: string;
|
allowedAccountIds: string;
|
||||||
@@ -124,7 +125,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;
|
||||||
@@ -138,7 +139,7 @@ export type AddIdentityAwsIamAuthDTO = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateIdentityAwsIamAuthDTO = {
|
export type UpdateIdentityAwsAuthDTO = {
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
identityId: string;
|
identityId: string;
|
||||||
stsEndpoint?: string;
|
stsEndpoint?: string;
|
||||||
|
@@ -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 { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
import { IdentityUniversalAuthForm } from "./IdentityUniversalAuthForm";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -28,7 +28,7 @@ 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: "AWS Auth", value: IdentityAuthMethod.AWS_AUTH }
|
||||||
];
|
];
|
||||||
|
|
||||||
const schema = yup
|
const schema = yup
|
||||||
@@ -66,9 +66,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}
|
||||||
|
@@ -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,
|
Reference in New Issue
Block a user