Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/src/@types/fastify.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import { TAllowedFields } from "@app/services/identity-ldap-auth/identity-ldap-a
import { TIdentityOciAuthServiceFactory } from "@app/services/identity-oci-auth/identity-oci-auth-service";
import { TIdentityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth/identity-oidc-auth-service";
import { TIdentityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
import { TIdentitySpiffeAuthServiceFactory } from "@app/services/identity-spiffe-auth/identity-spiffe-auth-service";
import { TIdentityTlsCertAuthServiceFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-types";
import { TIdentityTokenAuthServiceFactory } from "@app/services/identity-token-auth/identity-token-auth-service";
import { TIdentityUaServiceFactory } from "@app/services/identity-ua/identity-ua-service";
Expand Down Expand Up @@ -287,6 +288,7 @@ declare module "fastify" {
identityOciAuth: TIdentityOciAuthServiceFactory;
identityOidcAuth: TIdentityOidcAuthServiceFactory;
identityJwtAuth: TIdentityJwtAuthServiceFactory;
identitySpiffeAuth: TIdentitySpiffeAuthServiceFactory;
identityLdapAuth: TIdentityLdapAuthServiceFactory;
accessApprovalPolicy: TAccessApprovalPolicyServiceFactory;
accessApprovalRequest: TAccessApprovalRequestServiceFactory;
Expand Down
10 changes: 10 additions & 0 deletions backend/src/@types/knex.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,11 @@ import {
TIdentityLdapAuthsInsert,
TIdentityLdapAuthsUpdate
} from "@app/db/schemas/identity-ldap-auths";
import {
TIdentitySpiffeAuths,
TIdentitySpiffeAuthsInsert,
TIdentitySpiffeAuthsUpdate
} from "@app/db/schemas/identity-spiffe-auths";
import {
TMicrosoftTeamsIntegrations,
TMicrosoftTeamsIntegrationsInsert,
Expand Down Expand Up @@ -1070,6 +1075,11 @@ declare module "knex/types/tables" {
TIdentityLdapAuthsInsert,
TIdentityLdapAuthsUpdate
>;
[TableName.IdentitySpiffeAuth]: KnexOriginal.CompositeTableType<
TIdentitySpiffeAuths,
TIdentitySpiffeAuthsInsert,
TIdentitySpiffeAuthsUpdate
>;
[TableName.IdentityUaClientSecret]: KnexOriginal.CompositeTableType<
TIdentityUaClientSecrets,
TIdentityUaClientSecretsInsert,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Knex } from "knex";

import { TableName } from "../schemas";
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";

export async function up(knex: Knex): Promise<void> {
if (!(await knex.schema.hasTable(TableName.IdentitySpiffeAuth))) {
await knex.schema.createTable(TableName.IdentitySpiffeAuth, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.uuid("identityId").notNullable().unique();
t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE");
t.string("trustDomain").notNullable();
t.string("allowedSpiffeIds").notNullable();
t.string("allowedAudiences").notNullable();
t.string("configurationType").notNullable();
t.binary("encryptedCaBundleJwks").nullable();
t.string("bundleEndpointUrl").nullable();
t.string("bundleEndpointProfile").nullable();
t.binary("encryptedBundleEndpointCaCert").nullable();
t.binary("encryptedCachedBundleJwks").nullable();
t.datetime("cachedBundleLastRefreshedAt").nullable();
t.integer("bundleRefreshHintSeconds").defaultTo(300).notNullable();
t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable();
t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable();
t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable();
t.jsonb("accessTokenTrustedIps").notNullable();
t.timestamps(true, true, true);
});
}

await createOnUpdateTrigger(knex, TableName.IdentitySpiffeAuth);
}

export async function down(knex: Knex): Promise<void> {
await knex.schema.dropTableIfExists(TableName.IdentitySpiffeAuth);
await dropOnUpdateTrigger(knex, TableName.IdentitySpiffeAuth);
}
36 changes: 36 additions & 0 deletions backend/src/db/schemas/identity-spiffe-auths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Code generated by automation script, DO NOT EDIT.
// Automated by pulling database and generating zod schema
// To update. Just run npm run generate:schema
// Written by akhilmhdh.

import { z } from "zod";

import { zodBuffer } from "@app/lib/zod";

import { TImmutableDBKeys } from "./models";

export const IdentitySpiffeAuthsSchema = z.object({
id: z.string().uuid(),
identityId: z.string().uuid(),
trustDomain: z.string(),
allowedSpiffeIds: z.string(),
allowedAudiences: z.string(),
configurationType: z.string(),
encryptedCaBundleJwks: zodBuffer.nullable().optional(),
bundleEndpointUrl: z.string().nullable().optional(),
bundleEndpointProfile: z.string().nullable().optional(),
encryptedBundleEndpointCaCert: zodBuffer.nullable().optional(),
encryptedCachedBundleJwks: zodBuffer.nullable().optional(),
cachedBundleLastRefreshedAt: z.date().nullable().optional(),
bundleRefreshHintSeconds: z.coerce.number().default(300),
accessTokenTTL: z.coerce.number().default(7200),
accessTokenMaxTTL: z.coerce.number().default(7200),
accessTokenNumUsesLimit: z.coerce.number().default(0),
accessTokenTrustedIps: z.unknown(),
createdAt: z.date(),
updatedAt: z.date()
});

export type TIdentitySpiffeAuths = z.infer<typeof IdentitySpiffeAuthsSchema>;
export type TIdentitySpiffeAuthsInsert = Omit<z.input<typeof IdentitySpiffeAuthsSchema>, TImmutableDBKeys>;
export type TIdentitySpiffeAuthsUpdate = Partial<Omit<z.input<typeof IdentitySpiffeAuthsSchema>, TImmutableDBKeys>>;
1 change: 1 addition & 0 deletions backend/src/db/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export * from "./identity-org-memberships";
export * from "./identity-project-additional-privilege";
export * from "./identity-project-membership-role";
export * from "./identity-project-memberships";
export * from "./identity-spiffe-auths";
export * from "./identity-tls-cert-auths";
export * from "./identity-token-auths";
export * from "./identity-ua-client-secrets";
Expand Down
4 changes: 3 additions & 1 deletion backend/src/db/schemas/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export enum TableName {
IdentityJwtAuth = "identity_jwt_auths",
IdentityLdapAuth = "identity_ldap_auths",
IdentityTlsCertAuth = "identity_tls_cert_auths",
IdentitySpiffeAuth = "identity_spiffe_auths",
IdentityOrgMembership = "identity_org_memberships",
IdentityProjectMembership = "identity_project_memberships",
IdentityProjectMembershipRole = "identity_project_membership_role",
Expand Down Expand Up @@ -343,7 +344,8 @@ export enum IdentityAuthMethod {
OCI_AUTH = "oci-auth",
OIDC_AUTH = "oidc-auth",
JWT_AUTH = "jwt-auth",
LDAP_AUTH = "ldap-auth"
LDAP_AUTH = "ldap-auth",
SPIFFE_AUTH = "spiffe-auth"
}

export enum ProjectType {
Expand Down
73 changes: 73 additions & 0 deletions backend/src/ee/services/audit-log/audit-log-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ export enum EventType {
GET_IDENTITY_JWT_AUTH = "get-identity-jwt-auth",
REVOKE_IDENTITY_JWT_AUTH = "revoke-identity-jwt-auth",

LOGIN_IDENTITY_SPIFFE_AUTH = "login-identity-spiffe-auth",
ADD_IDENTITY_SPIFFE_AUTH = "add-identity-spiffe-auth",
UPDATE_IDENTITY_SPIFFE_AUTH = "update-identity-spiffe-auth",
GET_IDENTITY_SPIFFE_AUTH = "get-identity-spiffe-auth",
REVOKE_IDENTITY_SPIFFE_AUTH = "revoke-identity-spiffe-auth",
REFRESH_IDENTITY_SPIFFE_AUTH_BUNDLE = "refresh-identity-spiffe-auth-bundle",

CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "create-identity-universal-auth-client-secret",
REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET = "revoke-identity-universal-auth-client-secret",
CLEAR_IDENTITY_UNIVERSAL_AUTH_LOCKOUTS = "clear-identity-universal-auth-lockouts",
Expand Down Expand Up @@ -1840,6 +1847,66 @@ interface GetIdentityJwtAuthEvent {
};
}

interface LoginIdentitySpiffeAuthEvent {
type: EventType.LOGIN_IDENTITY_SPIFFE_AUTH;
metadata: {
identityId: string;
identitySpiffeAuthId: string;
identityAccessTokenId: string;
};
}

interface AddIdentitySpiffeAuthEvent {
type: EventType.ADD_IDENTITY_SPIFFE_AUTH;
metadata: {
identityId: string;
trustDomain: string;
allowedSpiffeIds: string;
allowedAudiences: string;
configurationType: string;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: Array<TIdentityTrustedIp>;
};
}

interface UpdateIdentitySpiffeAuthEvent {
type: EventType.UPDATE_IDENTITY_SPIFFE_AUTH;
metadata: {
identityId: string;
trustDomain?: string;
allowedSpiffeIds?: string;
allowedAudiences?: string;
configurationType?: string;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;
accessTokenTrustedIps?: Array<TIdentityTrustedIp>;
};
}

interface DeleteIdentitySpiffeAuthEvent {
type: EventType.REVOKE_IDENTITY_SPIFFE_AUTH;
metadata: {
identityId: string;
};
}

interface GetIdentitySpiffeAuthEvent {
type: EventType.GET_IDENTITY_SPIFFE_AUTH;
metadata: {
identityId: string;
};
}

interface RefreshIdentitySpiffeAuthBundleEvent {
type: EventType.REFRESH_IDENTITY_SPIFFE_AUTH_BUNDLE;
metadata: {
identityId: string;
};
}

interface CreateEnvironmentEvent {
type: EventType.CREATE_ENVIRONMENT;
metadata: {
Expand Down Expand Up @@ -5171,6 +5238,12 @@ export type Event =
| UpdateIdentityJwtAuthEvent
| GetIdentityJwtAuthEvent
| DeleteIdentityJwtAuthEvent
| LoginIdentitySpiffeAuthEvent
| AddIdentitySpiffeAuthEvent
| UpdateIdentitySpiffeAuthEvent
| GetIdentitySpiffeAuthEvent
| RefreshIdentitySpiffeAuthBundleEvent
| DeleteIdentitySpiffeAuthEvent
| LoginIdentityLdapAuthEvent
| AddIdentityLdapAuthEvent
| UpdateIdentityLdapAuthEvent
Expand Down
56 changes: 56 additions & 0 deletions backend/src/lib/api-docs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export enum ApiDocsTags {
AzureAuth = "Azure Auth",
KubernetesAuth = "Kubernetes Auth",
JwtAuth = "JWT Auth",
SpiffeAuth = "SPIFFE Auth",
OidcAuth = "OIDC Auth",
LdapAuth = "LDAP Auth",
Groups = "Groups",
Expand Down Expand Up @@ -745,6 +746,61 @@ export const JWT_AUTH = {
}
} as const;

export const SPIFFE_AUTH = {
LOGIN: {
identityId: "The ID of the machine identity to login.",
jwt: "The JWT-SVID token to authenticate with.",
organizationSlug: IDENTITY_AUTH_SUB_ORGANIZATION_NAME
},
ATTACH: {
identityId: "The ID of the machine identity to attach the configuration onto.",
trustDomain: "The SPIFFE trust domain (e.g. prod.example.com).",
allowedSpiffeIds:
"Comma-separated list of allowed SPIFFE ID patterns. Supports picomatch glob patterns (e.g. spiffe://prod.example.com/**).",
allowedAudiences: "Comma-separated list of allowed audiences for JWT-SVID validation.",
configurationType:
"The configuration type for trust bundle management. Must be one of: 'static' (admin uploads JWKS), 'remote' (auto-refresh from SPIRE bundle endpoint).",
caBundleJwks:
"The JWKS JSON containing public keys for JWT-SVID verification. Required if configurationType is 'static'.",
bundleEndpointUrl:
"The SPIRE bundle endpoint URL for automatic trust bundle retrieval. Required if configurationType is 'remote'.",
bundleEndpointProfile:
"The bundle endpoint authentication profile. Must be one of: 'https_web' (standard HTTPS), 'https_spiffe' (mTLS with SPIFFE auth).",
bundleEndpointCaCert:
"The PEM-encoded CA certificate for verifying the bundle endpoint TLS connection. Required when bundleEndpointProfile is 'https_spiffe'.",
bundleRefreshHintSeconds: "The interval in seconds between bundle refresh attempts. Defaults to 300.",
accessTokenTrustedIps: "The IPs or CIDR ranges that access tokens can be used from.",
accessTokenTTL: "The lifetime for an access token in seconds.",
accessTokenMaxTTL: "The maximum lifetime for an access token in seconds.",
accessTokenNumUsesLimit: "The maximum number of times that an access token can be used."
},
UPDATE: {
identityId: "The ID of the machine identity to update the auth method for.",
trustDomain: "The new SPIFFE trust domain.",
allowedSpiffeIds: "The new comma-separated list of allowed SPIFFE ID patterns.",
allowedAudiences: "The new comma-separated list of allowed audiences.",
configurationType: "The new configuration type for trust bundle management.",
caBundleJwks: "The new JWKS JSON containing public keys.",
bundleEndpointUrl: "The new SPIRE bundle endpoint URL.",
bundleEndpointProfile: "The new bundle endpoint authentication profile.",
bundleEndpointCaCert: "The new PEM-encoded CA certificate for the bundle endpoint.",
bundleRefreshHintSeconds: "The new interval in seconds between bundle refresh attempts.",
accessTokenTrustedIps: "The new IPs or CIDR ranges that access tokens can be used from.",
accessTokenTTL: "The new lifetime for an access token in seconds.",
accessTokenMaxTTL: "The new maximum lifetime for an access token in seconds.",
accessTokenNumUsesLimit: "The new maximum number of times that an access token can be used."
},
RETRIEVE: {
identityId: "The ID of the machine identity to retrieve the auth method for."
},
REVOKE: {
identityId: "The ID of the machine identity to revoke the auth method for."
},
REFRESH: {
identityId: "The ID of the machine identity to force-refresh the cached SPIFFE trust bundle for."
}
} as const;

export const ORGANIZATIONS = {
LIST_USER_MEMBERSHIPS: {
organizationId: "The ID of the organization to get memberships from."
Expand Down
3 changes: 2 additions & 1 deletion backend/src/lib/telemetry/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ export enum AuthAttemptAuthMethod {
OCI_AUTH = "oci-auth",
OIDC_AUTH = "oidc-auth",
JWT_AUTH = "jwt-auth",
LDAP_AUTH = "ldap-auth"
LDAP_AUTH = "ldap-auth",
SPIFFE_AUTH = "spiffe-auth"
}

export enum AuthAttemptAuthResult {
Expand Down
15 changes: 15 additions & 0 deletions backend/src/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ import { identityOidcAuthDALFactory } from "@app/services/identity-oidc-auth/ide
import { identityOidcAuthServiceFactory } from "@app/services/identity-oidc-auth/identity-oidc-auth-service";
import { identityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
import { identityProjectServiceFactory } from "@app/services/identity-project/identity-project-service";
import { identitySpiffeAuthDALFactory } from "@app/services/identity-spiffe-auth/identity-spiffe-auth-dal";
import { identitySpiffeAuthServiceFactory } from "@app/services/identity-spiffe-auth/identity-spiffe-auth-service";
import { identityTlsCertAuthDALFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-dal";
import { identityTlsCertAuthServiceFactory } from "@app/services/identity-tls-cert-auth/identity-tls-cert-auth-service";
import { identityTokenAuthDALFactory } from "@app/services/identity-token-auth/identity-token-auth-dal";
Expand Down Expand Up @@ -527,6 +529,7 @@ export const registerRoutes = async (
const identityOciAuthDAL = identityOciAuthDALFactory(db);
const identityOidcAuthDAL = identityOidcAuthDALFactory(db);
const identityJwtAuthDAL = identityJwtAuthDALFactory(db);
const identitySpiffeAuthDAL = identitySpiffeAuthDALFactory(db);
const identityAzureAuthDAL = identityAzureAuthDALFactory(db);
const identityLdapAuthDAL = identityLdapAuthDALFactory(db);

Expand Down Expand Up @@ -1950,6 +1953,17 @@ export const registerRoutes = async (
membershipIdentityDAL
});

const identitySpiffeAuthService = identitySpiffeAuthServiceFactory({
identityDAL,
identitySpiffeAuthDAL,
orgDAL,
permissionService,
identityAccessTokenDAL,
licenseService,
kmsService,
membershipIdentityDAL
});

const identityLdapAuthService = identityLdapAuthServiceFactory({
identityLdapAuthDAL,
orgDAL,
Expand Down Expand Up @@ -2832,6 +2846,7 @@ export const registerRoutes = async (
identityTlsCertAuth: identityTlsCertAuthService,
identityOidcAuth: identityOidcAuthService,
identityJwtAuth: identityJwtAuthService,
identitySpiffeAuth: identitySpiffeAuthService,
identityLdapAuth: identityLdapAuthService,
accessApprovalPolicy: accessApprovalPolicyService,
accessApprovalRequest: accessApprovalRequestService,
Expand Down
Loading
Loading