Compare commits

..

9 Commits

Author SHA1 Message Date
Maidul Islam
fed44f328d Merge pull request #2133 from akhilmhdh/feat/aws-kms-sm
fix: slug too big for project fixed
2024-07-16 09:50:08 -04:00
BlackMagiq
95a68f2c2d Merge pull request #2134 from Infisical/improve-auth-method-errors
Improve Native Auth Method Forbidden Errors
2024-07-16 15:00:12 +07:00
BlackMagiq
db7c0c45f6 Merge pull request #2135 from Infisical/fix-identity-projects
Fix Identity-Project Provisioning Modal — Filter Current Org Projects
2024-07-16 14:59:41 +07:00
Tuan Dang
82bca03162 Filter out only projects that are part of current org in identity project modal 2024-07-16 14:31:40 +07:00
Tuan Dang
043c04778f Improve native auth method unauthorized errors 2024-07-16 13:47:46 +07:00
=
560cd81a1c fix: slug too big for project fixed 2024-07-16 11:26:45 +05:30
Daniel Hougaard
df3a87fabf Merge pull request #2132 from Infisical/daniel/operator-azure-fix
feat(k8-operator): customizable azure auth resource url
2024-07-16 06:29:13 +02:00
Daniel Hougaard
9b0b14b847 Merge pull request #2131 from Infisical/daniel/azure-fix
fix(auth): Azure audience formatting bug
2024-07-16 04:50:49 +02:00
Daniel Hougaard
7ed8feee6f Update identity-azure-auth-fns.ts 2024-07-16 04:15:04 +02:00
9 changed files with 68 additions and 24 deletions

View File

@@ -39,7 +39,7 @@ export const registerExternalKmsRouter = async (server: FastifyZodProvider) => {
},
schema: {
body: z.object({
slug: z.string().min(1).trim().optional(),
slug: z.string().min(1).trim().toLowerCase().optional(),
description: z.string().min(1).trim().optional(),
provider: ExternalKmsInputSchema
}),
@@ -75,7 +75,7 @@ export const registerExternalKmsRouter = async (server: FastifyZodProvider) => {
id: z.string().trim().min(1)
}),
body: z.object({
slug: z.string().min(1).trim().optional(),
slug: z.string().min(1).trim().toLowerCase().optional(),
description: z.string().min(1).trim().optional(),
provider: ExternalKmsInputUpdateSchema
}),

View File

@@ -52,7 +52,7 @@ export const externalKmsServiceFactory = ({
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
const kmsSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(32));
const kmsSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(8).toLowerCase());
let sanitizedProviderInput = "";
switch (provider.type) {

View File

@@ -78,7 +78,10 @@ export const identityAwsAuthServiceFactory = ({
.map((accountId) => accountId.trim())
.some((accountId) => accountId === Account);
if (!isAccountAllowed) throw new UnauthorizedError();
if (!isAccountAllowed)
throw new ForbiddenRequestError({
message: "Access denied: AWS account ID not allowed."
});
}
if (identityAwsAuth.allowedPrincipalArns) {
@@ -94,7 +97,10 @@ export const identityAwsAuthServiceFactory = ({
return regex.test(extractPrincipalArn(Arn));
});
if (!isArnAllowed) throw new UnauthorizedError();
if (!isArnAllowed)
throw new ForbiddenRequestError({
message: "Access denied: AWS principal ARN not allowed."
});
}
const identityAccessToken = await identityAwsAuthDAL.transaction(async (tx) => {

View File

@@ -17,6 +17,7 @@ export const validateAzureIdentity = async ({
const jwksUri = `https://login.microsoftonline.com/${tenantId}/discovery/keys`;
const decodedJwt = jwt.decode(azureJwt, { complete: true }) as TDecodedAzureAuthJwt;
const { kid } = decodedJwt.header;
const { data }: { data: TAzureJwksUriResponse } = await axios.get(jwksUri);
@@ -27,6 +28,13 @@ export const validateAzureIdentity = async ({
const publicKey = `-----BEGIN CERTIFICATE-----\n${signingKey.x5c[0]}\n-----END CERTIFICATE-----`;
// Case: This can happen when the user uses a custom resource (such as https://management.azure.com&client_id=value).
// In this case, the audience in the decoded JWT will not have a trailing slash, but the resource will.
if (!decodedJwt.payload.aud.endsWith("/") && resource.endsWith("/")) {
// eslint-disable-next-line no-param-reassign
resource = resource.slice(0, -1);
}
return jwt.verify(azureJwt, publicKey, {
audience: resource,
issuer: `https://sts.windows.net/${tenantId}/`

View File

@@ -81,7 +81,10 @@ export const identityGcpAuthServiceFactory = ({
.map((serviceAccount) => serviceAccount.trim())
.some((serviceAccount) => serviceAccount === gcpIdentityDetails.email);
if (!isServiceAccountAllowed) throw new UnauthorizedError();
if (!isServiceAccountAllowed)
throw new ForbiddenRequestError({
message: "Access denied: GCP service account not allowed."
});
}
if (identityGcpAuth.type === "gce" && identityGcpAuth.allowedProjects && gcpIdentityDetails.computeEngineDetails) {
@@ -92,7 +95,10 @@ export const identityGcpAuthServiceFactory = ({
.map((project) => project.trim())
.some((project) => project === gcpIdentityDetails.computeEngineDetails?.project_id);
if (!isProjectAllowed) throw new UnauthorizedError();
if (!isProjectAllowed)
throw new ForbiddenRequestError({
message: "Access denied: GCP project not allowed."
});
}
if (identityGcpAuth.type === "gce" && identityGcpAuth.allowedZones && gcpIdentityDetails.computeEngineDetails) {
@@ -101,7 +107,10 @@ export const identityGcpAuthServiceFactory = ({
.map((zone) => zone.trim())
.some((zone) => zone === gcpIdentityDetails.computeEngineDetails?.zone);
if (!isZoneAllowed) throw new UnauthorizedError();
if (!isZoneAllowed)
throw new ForbiddenRequestError({
message: "Access denied: GCP zone not allowed."
});
}
const identityAccessToken = await identityGcpAuthDAL.transaction(async (tx) => {

View File

@@ -139,7 +139,10 @@ export const identityKubernetesAuthServiceFactory = ({
.map((namespace) => namespace.trim())
.some((namespace) => namespace === targetNamespace);
if (!isNamespaceAllowed) throw new UnauthorizedError();
if (!isNamespaceAllowed)
throw new ForbiddenRequestError({
message: "Access denied: K8s namespace not allowed."
});
}
if (identityKubernetesAuth.allowedNames) {
@@ -150,7 +153,10 @@ export const identityKubernetesAuthServiceFactory = ({
.map((name) => name.trim())
.some((name) => name === targetName);
if (!isNameAllowed) throw new UnauthorizedError();
if (!isNameAllowed)
throw new ForbiddenRequestError({
message: "Access denied: K8s name not allowed."
});
}
if (identityKubernetesAuth.allowedAudience) {
@@ -159,7 +165,10 @@ export const identityKubernetesAuthServiceFactory = ({
(audience) => audience === identityKubernetesAuth.allowedAudience
);
if (!isAudienceAllowed) throw new UnauthorizedError();
if (!isAudienceAllowed)
throw new ForbiddenRequestError({
message: "Access denied: K8s audience not allowed."
});
}
const identityAccessToken = await identityKubernetesAuthDAL.transaction(async (tx) => {

View File

@@ -124,13 +124,17 @@ export const identityOidcAuthServiceFactory = ({
if (identityOidcAuth.boundSubject) {
if (tokenData.sub !== identityOidcAuth.boundSubject) {
throw new UnauthorizedError();
throw new ForbiddenRequestError({
message: "Access denied: OIDC subject not allowed."
});
}
}
if (identityOidcAuth.boundAudiences) {
if (!identityOidcAuth.boundAudiences.split(", ").includes(tokenData.aud)) {
throw new UnauthorizedError();
throw new ForbiddenRequestError({
message: "Access denied: OIDC audience not allowed."
});
}
}
@@ -139,7 +143,9 @@ export const identityOidcAuthServiceFactory = ({
const claimValue = (identityOidcAuth.boundClaims as Record<string, string>)[claimKey];
// handle both single and multi-valued claims
if (!claimValue.split(", ").some((claimEntry) => tokenData[claimKey] === claimEntry)) {
throw new UnauthorizedError();
throw new ForbiddenRequestError({
message: "Access denied: OIDC claim not allowed."
});
}
});
}

View File

@@ -56,15 +56,18 @@ export const kmsServiceFactory = ({
const cipher = symmetricCipherService(SymmetricEncryption.AES_GCM_256);
const kmsKeyMaterial = randomSecureBytes(32);
const encryptedKeyMaterial = cipher.encrypt(kmsKeyMaterial, ROOT_ENCRYPTION_KEY);
const sanitizedSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(32));
const sanitizedSlug = slug ? slugify(slug) : slugify(alphaNumericNanoId(8).toLowerCase());
const dbQuery = async (db: Knex) => {
const kmsDoc = await kmsDAL.create({
slug: sanitizedSlug,
orgId,
isReserved
});
const kmsDoc = await kmsDAL.create(
{
slug: sanitizedSlug,
orgId,
isReserved
},
db
);
const { encryptedKey, ...doc } = await internalKmsDAL.create(
await internalKmsDAL.create(
{
version: 1,
encryptedKey: encryptedKeyMaterial,
@@ -73,7 +76,7 @@ export const kmsServiceFactory = ({
},
db
);
return doc;
return kmsDoc;
};
if (tx) return dbQuery(tx);
const doc = await kmsDAL.transaction(async (tx2) => dbQuery(tx2));

View File

@@ -5,7 +5,7 @@ import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Modal, ModalContent, Select, SelectItem } from "@app/components/v2";
import { useWorkspace } from "@app/context";
import { useOrganization,useWorkspace } from "@app/context";
import {
useAddIdentityToWorkspace,
useGetIdentityProjectMemberships,
@@ -33,6 +33,7 @@ type Props = {
};
export const IdentityAddToProjectModal = ({ identityId, popUp, handlePopUpToggle }: Props) => {
const { currentOrg } = useOrganization();
const { workspaces } = useWorkspace();
const { mutateAsync: addIdentityToWorkspace } = useAddIdentityToWorkspace();
@@ -58,7 +59,9 @@ export const IdentityAddToProjectModal = ({ identityId, popUp, handlePopUpToggle
wsWorkspaceIds.set(projectMembership.project.id, true);
});
return (workspaces || []).filter(({ id }) => !wsWorkspaceIds.has(id));
return (workspaces || []).filter(
({ id, orgId }) => !wsWorkspaceIds.has(id) && orgId === currentOrg?.id
);
}, [workspaces, projectMemberships]);
const onFormSubmit = async ({ projectId: workspaceId, role }: FormData) => {