Skip to content

Commit ce546f1

Browse files
feat: Implement SFI cred change
2 parents 911638d + 2e1701b commit ce546f1

File tree

8 files changed

+66
-10
lines changed

8 files changed

+66
-10
lines changed

infra/main.bicep

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,10 @@ module containerAppBackend 'br/public:avm/res/app/container-app:0.17.0' = {
530530
name: 'AZURE_CLIENT_ID'
531531
value: appIdentity.outputs.clientId // NOTE: This is the client ID of the managed identity, not the Entra application, and is needed for the App Service to access the Cosmos DB account.
532532
}
533+
{
534+
name: 'APP_ENV'
535+
value: 'prod'
536+
}
533537
],
534538
enableMonitoring
535539
? [
@@ -604,6 +608,10 @@ module containerAppFrontend 'br/public:avm/res/app/container-app:0.17.0' = {
604608
name: 'API_URL'
605609
value: 'https://${containerAppBackend.outputs.fqdn}'
606610
}
611+
{
612+
name: 'APP_ENV'
613+
value: 'prod'
614+
}
607615
]
608616
image: 'cmsacontainerreg.azurecr.io/cmsafrontend:${imageVersion}'
609617
name: 'cmsafrontend'

infra/main.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"_generator": {
77
"name": "bicep",
88
"version": "0.36.177.2456",
9-
"templateHash": "9967677186411813072"
9+
"templateHash": "12716753818171697569"
1010
},
1111
"name": "Modernize Your Code Solution Accelerator",
1212
"description": "CSA CTO Gold Standard Solution Accelerator for Modernize Your Code. \r\n"
@@ -41832,7 +41832,7 @@
4183241832
{
4183341833
"name": "cmsabackend",
4183441834
"image": "[format('cmsacontainerreg.azurecr.io/cmsabackend:{0}', parameters('imageVersion'))]",
41835-
"env": "[concat(createArray(createObject('name', 'COSMOSDB_ENDPOINT', 'value', reference('cosmosDb').outputs.endpoint.value), createObject('name', 'COSMOSDB_DATABASE', 'value', reference('cosmosDb').outputs.databaseName.value), createObject('name', 'COSMOSDB_BATCH_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.batch), createObject('name', 'COSMOSDB_FILE_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.file), createObject('name', 'COSMOSDB_LOG_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.log), createObject('name', 'AZURE_BLOB_ACCOUNT_NAME', 'value', reference('storageAccount').outputs.name.value), createObject('name', 'AZURE_BLOB_CONTAINER_NAME', 'value', variables('appStorageContainerName')), createObject('name', 'AZURE_OPENAI_ENDPOINT', 'value', format('https://{0}.openai.azure.com/', reference('aiServices').outputs.name.value)), createObject('name', 'MIGRATOR_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'PICKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'FIXER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SEMANTIC_VERIFIER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SYNTAX_CHECKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SELECTION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'TERMINATION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME', 'value', variables('modelDeployment').name), createObject('name', 'AI_PROJECT_ENDPOINT', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_NAME', 'value', reference('aiServices').outputs.aiProjectInfo.value.name), createObject('name', 'AZURE_AI_AGENT_RESOURCE_GROUP_NAME', 'value', resourceGroup().name), createObject('name', 'AZURE_AI_AGENT_SUBSCRIPTION_ID', 'value', subscription().subscriptionId), createObject('name', 'AZURE_AI_AGENT_ENDPOINT', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_CLIENT_ID', 'value', reference('appIdentity').outputs.clientId.value)), if(parameters('enableMonitoring'), createArray(createObject('name', 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY', 'value', reference('applicationInsights').outputs.instrumentationKey.value), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference('applicationInsights').outputs.connectionString.value)), createArray()))]",
41835+
"env": "[concat(createArray(createObject('name', 'COSMOSDB_ENDPOINT', 'value', reference('cosmosDb').outputs.endpoint.value), createObject('name', 'COSMOSDB_DATABASE', 'value', reference('cosmosDb').outputs.databaseName.value), createObject('name', 'COSMOSDB_BATCH_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.batch), createObject('name', 'COSMOSDB_FILE_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.file), createObject('name', 'COSMOSDB_LOG_CONTAINER', 'value', reference('cosmosDb').outputs.containerNames.value.log), createObject('name', 'AZURE_BLOB_ACCOUNT_NAME', 'value', reference('storageAccount').outputs.name.value), createObject('name', 'AZURE_BLOB_CONTAINER_NAME', 'value', variables('appStorageContainerName')), createObject('name', 'AZURE_OPENAI_ENDPOINT', 'value', format('https://{0}.openai.azure.com/', reference('aiServices').outputs.name.value)), createObject('name', 'MIGRATOR_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'PICKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'FIXER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SEMANTIC_VERIFIER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SYNTAX_CHECKER_AGENT_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'SELECTION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'TERMINATION_MODEL_DEPLOY', 'value', variables('modelDeployment').name), createObject('name', 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME', 'value', variables('modelDeployment').name), createObject('name', 'AI_PROJECT_ENDPOINT', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_CONNECTION_STRING', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_AI_AGENT_PROJECT_NAME', 'value', reference('aiServices').outputs.aiProjectInfo.value.name), createObject('name', 'AZURE_AI_AGENT_RESOURCE_GROUP_NAME', 'value', resourceGroup().name), createObject('name', 'AZURE_AI_AGENT_SUBSCRIPTION_ID', 'value', subscription().subscriptionId), createObject('name', 'AZURE_AI_AGENT_ENDPOINT', 'value', reference('aiServices').outputs.aiProjectInfo.value.apiEndpoint), createObject('name', 'AZURE_CLIENT_ID', 'value', reference('appIdentity').outputs.clientId.value), createObject('name', 'APP_ENV', 'value', 'prod')), if(parameters('enableMonitoring'), createArray(createObject('name', 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY', 'value', reference('applicationInsights').outputs.instrumentationKey.value), createObject('name', 'APPLICATIONINSIGHTS_CONNECTION_STRING', 'value', reference('applicationInsights').outputs.connectionString.value)), createArray()))]",
4183641836
"resources": {
4183741837
"cpu": 1,
4183841838
"memory": "2.0Gi"
@@ -43334,6 +43334,10 @@
4333443334
{
4333543335
"name": "API_URL",
4333643336
"value": "[format('https://{0}', reference('containerAppBackend').outputs.fqdn.value)]"
43337+
},
43338+
{
43339+
"name": "APP_ENV",
43340+
"value": "prod"
4333743341
}
4333843342
],
4333943343
"image": "[format('cmsacontainerreg.azurecr.io/cmsafrontend:{0}', parameters('imageVersion'))]",

src/backend/.env.sample

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ AZURE_AI_AGENT_PROJECT_CONNECTION_STRING = ""
2323
AZURE_AI_AGENT_SUBSCRIPTION_ID = ""
2424
AZURE_AI_AGENT_RESOURCE_GROUP_NAME = ""
2525
AZURE_AI_AGENT_PROJECT_NAME = ""
26-
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = ""
26+
AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME = ""
27+
28+
APP_ENV = "dev"

src/backend/app.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
from api.api_routes import router as backend_router
55

6-
from azure.identity.aio import DefaultAzureCredential
7-
86
from common.config.config import app_config
97
from common.logger.app_logger import AppLogger
108

@@ -13,6 +11,8 @@
1311
from fastapi import FastAPI
1412
from fastapi.middleware.cors import CORSMiddleware
1513

14+
from helper.azure_credential_utils import get_azure_credential
15+
1616
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent # pylint: disable=E0611
1717

1818
from sql_agents.agent_manager import clear_sql_agents, set_sql_agents
@@ -43,7 +43,7 @@ async def lifespan(app: FastAPI):
4343
logger.logger.info("Initializing SQL agents...")
4444

4545
# Create Azure credentials and client
46-
creds = DefaultAzureCredential()
46+
creds = get_azure_credential(app_config.azure_client_id)
4747
azure_client = AzureAIAgent.create_client(
4848
credential=creds,
4949
endpoint=app_config.ai_project_endpoint

src/backend/common/config/config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414

1515
import os
1616

17-
from azure.identity.aio import ClientSecretCredential, DefaultAzureCredential
17+
from azure.identity.aio import ClientSecretCredential
18+
19+
from helper.azure_credential_utils import get_azure_credential
1820

1921

2022
class Config:
@@ -49,7 +51,7 @@ def __init__(self):
4951
"SYNTAX_CHECKER_AGENT_MODEL_DEPLOY"
5052
)
5153

52-
self.__azure_credentials = DefaultAzureCredential()
54+
self.__azure_credentials = get_azure_credential(self.azure_client_id)
5355

5456
def get_azure_credentials(self):
5557
"""Retrieve Azure credentials, either from environment variables or managed identity."""

src/backend/common/storage/blob_azure.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from typing import Any, BinaryIO, Dict, Optional
22

3-
from azure.identity import DefaultAzureCredential
43
from azure.storage.blob import BlobServiceClient
54

5+
from common.config.config import app_config
66
from common.logger.app_logger import AppLogger
77
from common.storage.blob_base import BlobStorageBase
88

9+
from helper.azure_credential_utils import get_azure_credential
10+
911

1012
class AzureBlobStorage(BlobStorageBase):
1113
def __init__(self, account_name: str, container_name: Optional[str] = None):
@@ -15,7 +17,7 @@ def __init__(self, account_name: str, container_name: Optional[str] = None):
1517
self.container_name = container_name
1618
self.service_client = None
1719
self.container_client = None
18-
credential = DefaultAzureCredential() # Using Entra Authentication
20+
credential = get_azure_credential(app_config.azure_client_id) # Using Entra Authentication
1921
self.service_client = BlobServiceClient(
2022
account_url=f"https://{self.account_name}.blob.core.windows.net/",
2123
credential=credential,
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import os
2+
3+
from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
4+
from azure.identity.aio import DefaultAzureCredential as AioDefaultAzureCredential, ManagedIdentityCredential as AioManagedIdentityCredential
5+
6+
7+
async def get_azure_credential_async(client_id=None):
8+
"""
9+
Returns an Azure credential asynchronously based on the application environment.
10+
If the environment is 'dev', it uses AioDefaultAzureCredential.
11+
Otherwise, it uses AioManagedIdentityCredential.
12+
Args:
13+
client_id (str, optional): The client ID for the Managed Identity Credential.
14+
Returns:
15+
Credential object: Either AioDefaultAzureCredential or AioManagedIdentityCredential.
16+
"""
17+
print(os.getenv("APP_ENV"))
18+
if os.getenv("APP_ENV", "prod").lower() == 'dev':
19+
return AioDefaultAzureCredential() # CodeQL [SM05139] Okay use of DefaultAzureCredential as it is only used in development
20+
else:
21+
return AioManagedIdentityCredential(client_id=client_id)
22+
23+
24+
def get_azure_credential(client_id=None):
25+
"""
26+
Returns an Azure credential based on the application environment.
27+
If the environment is 'dev', it uses DefaultAzureCredential.
28+
Otherwise, it uses ManagedIdentityCredential.
29+
Args:
30+
client_id (str, optional): The client ID for the Managed Identity Credential.
31+
Returns:
32+
Credential object: Either DefaultAzureCredential or ManagedIdentityCredential.
33+
"""
34+
if os.getenv("APP_ENV", "prod").lower() == 'dev':
35+
return DefaultAzureCredential() # CodeQL [SM05139] Okay use of DefaultAzureCredential as it is only used in development
36+
else:
37+
return ManagedIdentityCredential(client_id=client_id)

src/frontend/.env.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ ENABLE_AUTH=false
1111
# REACT_APP_MSAL_REDIRECT_URL="/"
1212
# REACT_APP_MSAL_POST_REDIRECT_URL="/"
1313

14+
APP_ENV = "dev"

0 commit comments

Comments
 (0)