diff --git a/cloudformation/iam.yml b/cloudformation/iam.yml index 7ced4b53..a978eba5 100644 --- a/cloudformation/iam.yml +++ b/cloudformation/iam.yml @@ -176,6 +176,7 @@ Resources: Effect: Allow Resource: - Fn::Sub: arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:infra-core-api-entra* + - Fn::Sub: arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:infra-core-api-ro-entra* # SQS Lambda IAM Role SqsLambdaIAMRole: diff --git a/src/api/functions/entraId.ts b/src/api/functions/entraId.ts index 44fbe6bf..815ebb3a 100644 --- a/src/api/functions/entraId.ts +++ b/src/api/functions/entraId.ts @@ -37,10 +37,13 @@ export async function getEntraIdToken( clients: { smClient: SecretsManagerClient; dynamoClient: DynamoDBClient }, clientId: string, scopes: string[] = ["https://graph.microsoft.com/.default"], + secretName?: string, ) { + if (!secretName) { + secretName = genericConfig.EntraSecretName; + } const secretApiConfig = - (await getSecretValue(clients.smClient, genericConfig.EntraSecretName)) || - {}; + (await getSecretValue(clients.smClient, secretName)) || {}; if ( !secretApiConfig.entra_id_private_key || !secretApiConfig.entra_id_thumbprint @@ -55,7 +58,7 @@ export async function getEntraIdToken( ).toString("utf8"); const cachedToken = await getItemFromCache( clients.dynamoClient, - "entra_id_access_token", + `entra_id_access_token_${secretName}`, ); if (cachedToken) { return cachedToken["token"] as string; @@ -85,7 +88,7 @@ export async function getEntraIdToken( if (result?.accessToken) { await insertItemIntoCache( clients.dynamoClient, - "entra_id_access_token", + `entra_id_access_token_${secretName}`, { token: result?.accessToken }, date, ); diff --git a/src/api/routes/iam.ts b/src/api/routes/iam.ts index b390bd1c..ae603d75 100644 --- a/src/api/routes/iam.ts +++ b/src/api/routes/iam.ts @@ -1,5 +1,5 @@ import { FastifyPluginAsync } from "fastify"; -import { allAppRoles, AppRoles } from "../../common/roles.js"; +import { AppRoles } from "../../common/roles.js"; import { zodToJsonSchema } from "zod-to-json-schema"; import { addToTenant, @@ -16,7 +16,6 @@ import { EntraInvitationError, InternalServerError, NotFoundError, - UnauthorizedError, } from "../../common/errors/index.js"; import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb"; import { genericConfig, roleArns } from "../../common/config.js"; @@ -465,7 +464,9 @@ const iamRoutes: FastifyPluginAsync = async (fastify, _options) => { } const entraIdToken = await getEntraIdToken( await getAuthorizedClients(), - fastify.environmentConfig.AadValidClientId, + fastify.environmentConfig.AadValidReadOnlyClientId, + undefined, + genericConfig.EntraReadOnlySecretName, ); const response = await listGroupMembers(entraIdToken, groupId); reply.status(200).send(response); diff --git a/src/api/routes/roomRequests.ts b/src/api/routes/roomRequests.ts index 90c91fb9..566675c9 100644 --- a/src/api/routes/roomRequests.ts +++ b/src/api/routes/roomRequests.ts @@ -3,7 +3,6 @@ import rateLimiter from "api/plugins/rateLimiter.js"; import { formatStatus, roomGetResponse, - roomRequestBaseSchema, RoomRequestFormValues, roomRequestPostResponse, roomRequestSchema, @@ -18,7 +17,6 @@ import { DatabaseFetchError, DatabaseInsertError, InternalServerError, - UnauthenticatedError, } from "common/errors/index.js"; import { PutItemCommand, @@ -27,7 +25,6 @@ import { } from "@aws-sdk/client-dynamodb"; import { genericConfig, notificationRecipients } from "common/config.js"; import { marshall, unmarshall } from "@aws-sdk/util-dynamodb"; -import { z } from "zod"; import { AvailableSQSFunctions, SQSPayload } from "common/types/sqsMessage.js"; import { SendMessageCommand, SQSClient } from "@aws-sdk/client-sqs"; diff --git a/src/common/config.ts b/src/common/config.ts index 86420366..2de9f783 100644 --- a/src/common/config.ts +++ b/src/common/config.ts @@ -20,6 +20,7 @@ export type ConfigType = { SqsQueueUrl: string; PaidMemberGroupId: string; PaidMemberPriceId: string; + AadValidReadOnlyClientId: string; }; export type GenericConfigType = { @@ -42,6 +43,7 @@ export type GenericConfigType = { ProtectedEntraIDGroups: string[]; // these groups are too privileged to be modified via this portal and must be modified directly in Entra ID. RoomRequestsTableName: string; RoomRequestsStatusTableName: string; + EntraReadOnlySecretName: string; }; type EnvironmentConfigType = { @@ -49,7 +51,7 @@ type EnvironmentConfigType = { }; export const infraChairsGroupId = "c0702752-50da-49da-83d4-bcbe6f7a9b1b"; -export const officersGroupId = "ff49e948-4587-416b-8224-65147540d5fc"; +export const officersGroupId = "c4ddcc9f-a9c0-47e7-98c1-f1b345d53121"; export const officersGroupTestingId = "0e6e9199-506f-4ede-9d1b-e73f6811c9e5"; export const execCouncilGroupId = "ad81254b-4eeb-4c96-8191-3acdce9194b1"; export const execCouncilTestingGroupId = "dbe18eb2-9675-46c4-b1ef-749a6db4fedd"; @@ -64,6 +66,7 @@ const genericConfig: GenericConfigType = { CacheDynamoTableName: "infra-core-api-cache", ConfigSecretName: "infra-core-api-config", EntraSecretName: "infra-core-api-entra", + EntraReadOnlySecretName: "infra-core-api-ro-entra", UpcomingEventThresholdSeconds: 1800, // 30 mins AwsRegion: process.env.AWS_REGION || "us-east-1", EntraTenantId: "c8d9148f-9a59-4db3-827d-42ea0c2b6e2e", @@ -99,6 +102,7 @@ const environmentConfig: EnvironmentConfigType = { "https://sqs.us-east-1.amazonaws.com/427040638965/infra-core-api-sqs", PaidMemberGroupId: "9222451f-b354-4e64-ba28-c0f367a277c2", PaidMemberPriceId: "price_1R4TcTDGHrJxx3mKI6XF9cNG", + AadValidReadOnlyClientId: "2c6a0057-5acc-496c-a4e5-4adbf88387ba" }, prod: { UserFacingUrl: "https://core.acm.illinois.edu", @@ -119,6 +123,7 @@ const environmentConfig: EnvironmentConfigType = { "https://sqs.us-east-1.amazonaws.com/298118738376/infra-core-api-sqs", PaidMemberGroupId: "172fd9ee-69f0-4384-9786-41ff1a43cf8e", PaidMemberPriceId: "price_1MUGIRDiGOXU9RuSChPYK6wZ", + AadValidReadOnlyClientId: "2c6a0057-5acc-496c-a4e5-4adbf88387ba" }, };