Skip to content

Commit 1a12376

Browse files
authored
Merge pull request lightspeed-core#988 from asimurka/azure-entra-id-final
LCORE-861: Azure Entra ID token managment
2 parents 6350993 + 4550d0b commit 1a12376

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1499
-538
lines changed

.github/workflows/e2e_tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
6161
cp "${CONFIG_FILE}" lightspeed-stack.yaml
6262
echo "✅ Configuration loaded successfully"
63-
63+
6464
- name: Select and configure run.yaml
6565
env:
6666
CONFIG_ENVIRONMENT: ${{ matrix.environment || 'ci' }}
@@ -100,7 +100,7 @@ jobs:
100100
echo "=== Configuration Summary ==="
101101
echo "Deployment mode: ${{ matrix.mode }}"
102102
echo "Environment: ${{ matrix.environment }}"
103-
echo "Source config: tests/e2e/configs/run-ci.yaml"
103+
echo "Source config: tests/e2e/configs/run-${{ matrix.environment }}.yaml"
104104
echo ""
105105
echo "=== Configuration Preview ==="
106106
echo "Providers: $(grep -c "provider_id:" run.yaml)"

.github/workflows/e2e_tests_providers.yaml

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ jobs:
5252
echo "=== Recent commits ==="
5353
git log --oneline -5
5454
55+
- name: Add Azure Entra ID config block to all test configs
56+
if: matrix.environment == 'azure'
57+
run: |
58+
echo "Adding azure_entra_id configuration block to all test configs..."
59+
for config in tests/e2e/configuration/*/lightspeed-stack*.yaml; do
60+
if [ -f "$config" ]; then
61+
echo "" >> "$config"
62+
echo "azure_entra_id:" >> "$config"
63+
echo " tenant_id: \${env.TENANT_ID}" >> "$config"
64+
echo " client_id: \${env.CLIENT_ID}" >> "$config"
65+
echo " client_secret: \${env.CLIENT_SECRET}" >> "$config"
66+
echo "✅ Added to: $config"
67+
fi
68+
done
69+
5570
- name: Load lightspeed-stack.yaml configuration
5671
run: |
5772
MODE="${{ matrix.mode }}"
@@ -66,32 +81,6 @@ jobs:
6681
6782
cp "${CONFIG_FILE}" lightspeed-stack.yaml
6883
echo "✅ Configuration loaded successfully"
69-
70-
- name: Get Azure API key (access token)
71-
if: matrix.environment == 'azure'
72-
id: azure_token
73-
env:
74-
CLIENT_ID: ${{ secrets.CLIENT_ID }}
75-
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
76-
TENANT_ID: ${{ secrets.TENANT_ID }}
77-
run: |
78-
echo "Requesting Azure API token..."
79-
RESPONSE=$(curl -s -X POST \
80-
-H "Content-Type: application/x-www-form-urlencoded" \
81-
-d "client_id=$CLIENT_ID&scope=https://cognitiveservices.azure.com/.default&client_secret=$CLIENT_SECRET&grant_type=client_credentials" \
82-
"https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token")
83-
84-
echo "Response received. Extracting access_token..."
85-
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.access_token')
86-
87-
if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" == "null" ]; then
88-
echo "❌ Failed to obtain Azure access token. Response:"
89-
echo "$RESPONSE"
90-
exit 1
91-
fi
92-
93-
echo "✅ Successfully obtained Azure access token."
94-
echo "AZURE_API_KEY=$ACCESS_TOKEN" >> $GITHUB_ENV
9584
9685
- name: Save VertexAI service account key to file
9786
if: matrix.environment == 'vertexai'
@@ -198,7 +187,9 @@ jobs:
198187
if: matrix.mode == 'server'
199188
env:
200189
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
201-
AZURE_API_KEY: ${{ env.AZURE_API_KEY }}
190+
TENANT_ID: ${{ secrets.TENANT_ID }}
191+
CLIENT_ID: ${{ secrets.CLIENT_ID }}
192+
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
202193
VERTEX_AI_LOCATION: ${{ secrets.VERTEX_AI_LOCATION }}
203194
VERTEX_AI_PROJECT: ${{ secrets.VERTEX_AI_PROJECT }}
204195
GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}
@@ -227,7 +218,9 @@ jobs:
227218
if: matrix.mode == 'library'
228219
env:
229220
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
230-
AZURE_API_KEY: ${{ env.AZURE_API_KEY }}
221+
TENANT_ID: ${{ secrets.TENANT_ID }}
222+
CLIENT_ID: ${{ secrets.CLIENT_ID }}
223+
CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
231224
VERTEX_AI_LOCATION: ${{ secrets.VERTEX_AI_LOCATION }}
232225
VERTEX_AI_PROJECT: ${{ secrets.VERTEX_AI_PROJECT }}
233226
GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}

.tekton/lightspeed-stack-pull-request.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ spec:
5555
],
5656
"requirements_build_files": ["requirements-build.txt"],
5757
"binary": {
58-
"packages": "accelerate,aiohappyeyeballs,aiohttp,aiosignal,aiosqlite,annotated-doc,annotated-types,anyio,asyncpg,attrs,autoevals,cachetools,cffi,charset-normalizer,chevron,click,cryptography,datasets,dill,distro,dnspython,durationpy,faiss-cpu,fire,frozenlist,fsspec,googleapis-common-protos,greenlet,grpcio,h11,hf-xet,httpcore,httpx,httpx-sse,huggingface-hub,idna,jinja2,jiter,joblib,jsonschema-specifications,llama-stack-client,lxml,markdown-it-py,markupsafe,mdurl,mpmath,multidict,networkx,nltk,numpy,oauthlib,opentelemetry-api,opentelemetry-exporter-otlp,opentelemetry-exporter-otlp-proto-common,opentelemetry-exporter-otlp-proto-grpc,opentelemetry-exporter-otlp-proto-http,opentelemetry-instrumentation,opentelemetry-proto,opentelemetry-sdk,opentelemetry-semantic-conventions,packaging,pandas,pillow,ply,polyleven,prompt-toolkit,propcache,proto-plus,psycopg2-binary,pyaml,pyarrow,pyasn1,pyasn1-modules,pycparser,pydantic,pydantic-core,pydantic-settings,pygments,pyjwt,python-dateutil,python-dotenv,python-multipart,pytz,pyyaml,referencing,regex,requests,requests-oauthlib,rich,rpds-py,rsa,safetensors,scikit-learn,scipy,sentence-transformers,setuptools,six,sniffio,sqlalchemy,starlette,sympy,threadpoolctl,tiktoken,tokenizers,torch,tqdm,transformers,triton,typing-extensions,typing-inspection,tzdata,urllib3,wcwidth,websocket-client,wrapt,xxhash,yarl,zipp,uv,pip,maturin",
58+
"packages": "accelerate,aiohappyeyeballs,aiohttp,aiosignal,aiosqlite,annotated-doc,annotated-types,anyio,asyncpg,attrs,autoevals,cachetools,cffi,charset-normalizer,chevron,click,cryptography,datasets,dill,distro,dnspython,durationpy,einops,faiss-cpu,fire,frozenlist,fsspec,googleapis-common-protos,greenlet,grpcio,h11,hf-xet,httpcore,httpx,httpx-sse,huggingface-hub,idna,jinja2,jiter,joblib,jsonschema-specifications,llama-stack-client,lxml,markdown-it-py,markupsafe,mdurl,mpmath,multidict,networkx,nltk,numpy,oauthlib,opentelemetry-api,opentelemetry-exporter-otlp,opentelemetry-exporter-otlp-proto-common,opentelemetry-exporter-otlp-proto-grpc,opentelemetry-exporter-otlp-proto-http,opentelemetry-instrumentation,opentelemetry-proto,opentelemetry-sdk,opentelemetry-semantic-conventions,packaging,pandas,pillow,ply,polyleven,prompt-toolkit,propcache,proto-plus,psycopg2-binary,pyaml,pyarrow,pyasn1,pyasn1-modules,pycparser,pydantic,pydantic-core,pydantic-settings,pygments,pyjwt,python-dateutil,python-dotenv,python-multipart,pytz,pyyaml,referencing,requests,requests-oauthlib,rich,rpds-py,rsa,safetensors,scikit-learn,scipy,sentence-transformers,setuptools,six,sniffio,sqlalchemy,starlette,sympy,threadpoolctl,tiktoken,tokenizers,torch,tqdm,transformers,triton,typing-extensions,typing-inspection,tzdata,urllib3,wcwidth,websocket-client,wrapt,xxhash,yarl,zipp,uv,pip,maturin",
5959
"os": "linux",
6060
"arch": "x86_64,aarch64",
6161
"py_version": "312"

.tekton/lightspeed-stack-push.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ spec:
4747
],
4848
"requirements_build_files": ["requirements-build.txt"],
4949
"binary": {
50-
"packages": "accelerate,aiohappyeyeballs,aiohttp,aiosignal,aiosqlite,annotated-doc,annotated-types,anyio,asyncpg,attrs,autoevals,cachetools,cffi,charset-normalizer,chevron,click,cryptography,datasets,dill,distro,dnspython,durationpy,faiss-cpu,fire,frozenlist,fsspec,googleapis-common-protos,greenlet,grpcio,h11,hf-xet,httpcore,httpx,httpx-sse,huggingface-hub,idna,jinja2,jiter,joblib,jsonschema-specifications,llama-stack-client,lxml,markdown-it-py,markupsafe,mdurl,mpmath,multidict,networkx,nltk,numpy,oauthlib,opentelemetry-api,opentelemetry-exporter-otlp,opentelemetry-exporter-otlp-proto-common,opentelemetry-exporter-otlp-proto-grpc,opentelemetry-exporter-otlp-proto-http,opentelemetry-instrumentation,opentelemetry-proto,opentelemetry-sdk,opentelemetry-semantic-conventions,packaging,pandas,pillow,ply,polyleven,prompt-toolkit,propcache,proto-plus,psycopg2-binary,pyaml,pyarrow,pyasn1,pyasn1-modules,pycparser,pydantic,pydantic-core,pydantic-settings,pygments,pyjwt,python-dateutil,python-dotenv,python-multipart,pytz,pyyaml,referencing,regex,requests,requests-oauthlib,rich,rpds-py,rsa,safetensors,scikit-learn,scipy,sentence-transformers,setuptools,six,sniffio,sqlalchemy,starlette,sympy,threadpoolctl,tiktoken,tokenizers,torch,tqdm,transformers,triton,typing-extensions,typing-inspection,tzdata,urllib3,wcwidth,websocket-client,wrapt,xxhash,yarl,zipp,uv,pip,maturin",
50+
"packages": "accelerate,aiohappyeyeballs,aiohttp,aiosignal,aiosqlite,annotated-doc,annotated-types,anyio,asyncpg,attrs,autoevals,cachetools,cffi,charset-normalizer,chevron,click,cryptography,datasets,dill,distro,dnspython,durationpy,einops,faiss-cpu,fire,frozenlist,fsspec,googleapis-common-protos,greenlet,grpcio,h11,hf-xet,httpcore,httpx,httpx-sse,huggingface-hub,idna,jinja2,jiter,joblib,jsonschema-specifications,llama-stack-client,lxml,markdown-it-py,markupsafe,mdurl,mpmath,multidict,networkx,nltk,numpy,oauthlib,opentelemetry-api,opentelemetry-exporter-otlp,opentelemetry-exporter-otlp-proto-common,opentelemetry-exporter-otlp-proto-grpc,opentelemetry-exporter-otlp-proto-http,opentelemetry-instrumentation,opentelemetry-proto,opentelemetry-sdk,opentelemetry-semantic-conventions,packaging,pandas,pillow,ply,polyleven,prompt-toolkit,propcache,proto-plus,psycopg2-binary,pyaml,pyarrow,pyasn1,pyasn1-modules,pycparser,pydantic,pydantic-core,pydantic-settings,pygments,pyjwt,python-dateutil,python-dotenv,python-multipart,pytz,pyyaml,referencing,requests,requests-oauthlib,rich,rpds-py,rsa,safetensors,scikit-learn,scipy,sentence-transformers,setuptools,six,sniffio,sqlalchemy,starlette,sympy,threadpoolctl,tiktoken,tokenizers,torch,tqdm,transformers,triton,typing-extensions,typing-inspection,tzdata,urllib3,wcwidth,websocket-client,wrapt,xxhash,yarl,zipp,uv,pip,maturin",
5151
"os": "linux",
5252
"arch": "x86_64,aarch64",
5353
"py_version": "312"

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@ PYTHON_REGISTRY = pypi
1010
TORCH_VERSION := 2.9.0
1111

1212

13+
# Default configuration files (override with: make run CONFIG=myconfig.yaml)
14+
CONFIG ?= lightspeed-stack.yaml
15+
LLAMA_STACK_CONFIG ?= run.yaml
16+
1317
run: ## Run the service locally
14-
uv run src/lightspeed_stack.py
18+
uv run src/lightspeed_stack.py -c $(CONFIG)
19+
20+
run-llama-stack: ## Start Llama Stack with enriched config (for local service mode)
21+
uv run src/llama_stack_configuration.py -c $(CONFIG) -i $(LLAMA_STACK_CONFIG) -o $(LLAMA_STACK_CONFIG) && \
22+
AZURE_API_KEY=$$(grep '^AZURE_API_KEY=' .env | cut -d'=' -f2-) \
23+
uv run llama stack run $(LLAMA_STACK_CONFIG)
1524

1625
test-unit: ## Run the unit tests
1726
@echo "Running unit tests..."

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ __Note__: Support for individual models is dependent on the specific inference p
203203
| RHOAI (vLLM)| meta-llama/Llama-3.2-1B-Instruct | Yes | remote::vllm | [1](tests/e2e-prow/rhoai/configs/run.yaml) |
204204
| RHAIIS (vLLM)| meta-llama/Llama-3.1-8B-Instruct | Yes | remote::vllm | [1](tests/e2e/configs/run-rhaiis.yaml) |
205205
| RHEL AI (vLLM)| meta-llama/Llama-3.1-8B-Instruct | Yes | remote::vllm | [1](tests/e2e/configs/run-rhelai.yaml) |
206-
| Azure | gpt-5, gpt-5-mini, gpt-5-nano, gpt-5-chat, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o3-mini, o4-mini | Yes | remote::azure | [1](examples/azure-run.yaml) |
207-
| Azure | o1, o1-mini | No | remote::azure | |
206+
| Azure | gpt-5, gpt-5-mini, gpt-5-nano, gpt-4o-mini, o3-mini, o4-mini, o1| Yes | remote::azure | [1](examples/azure-run.yaml) |
207+
| Azure | gpt-5-chat, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, o1-mini | No or limited | remote::azure | |
208208
| VertexAI | google/gemini-2.0-flash, google/gemini-2.5-flash, google/gemini-2.5-pro [^1] | Yes | remote::vertexai | [1](examples/vertexai-run.yaml) |
209209
| WatsonX | meta-llama/llama-3-3-70b-instruct | Yes | remote::watsonx | [1](examples/watsonx-run.yaml) |
210210

docker-compose-library.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ services:
1515
- ${GCP_KEYS_PATH:-./tmp/.gcp-keys-dummy}:/opt/app-root/.gcp-keys:ro
1616
- ./tests/e2e/rag:/opt/app-root/src/.llama/storage/rag:Z
1717
environment:
18+
# LLM Provider API Keys
1819
- BRAVE_SEARCH_API_KEY=${BRAVE_SEARCH_API_KEY:-}
1920
- TAVILY_SEARCH_API_KEY=${TAVILY_SEARCH_API_KEY:-}
2021
# OpenAI
2122
- OPENAI_API_KEY=${OPENAI_API_KEY}
2223
- E2E_OPENAI_MODEL=${E2E_OPENAI_MODEL:-gpt-4o-mini}
23-
# Azure
24-
- AZURE_API_KEY=${AZURE_API_KEY:-}
24+
# Azure Entra ID credentials (AZURE_API_KEY is obtained dynamically in Python)
25+
- TENANT_ID=${TENANT_ID:-}
26+
- CLIENT_ID=${CLIENT_ID:-}
27+
- CLIENT_SECRET=${CLIENT_SECRET:-}
2528
# RHAIIS
2629
- RHAIIS_URL=${RHAIIS_URL:-}
2730
- RHAIIS_API_KEY=${RHAIIS_API_KEY:-}

docker-compose.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ services:
1212
- ./run.yaml:/opt/app-root/run.yaml:Z
1313
- ${GCP_KEYS_PATH:-./tmp/.gcp-keys-dummy}:/opt/app-root/.gcp-keys:ro
1414
- ./tests/e2e/rag:/opt/app-root/src/.llama/storage/rag:Z
15+
- ./lightspeed-stack.yaml:/opt/app-root/lightspeed-stack.yaml:z
1516
environment:
1617
- BRAVE_SEARCH_API_KEY=${BRAVE_SEARCH_API_KEY:-}
1718
- TAVILY_SEARCH_API_KEY=${TAVILY_SEARCH_API_KEY:-}
1819
# OpenAI
1920
- OPENAI_API_KEY=${OPENAI_API_KEY}
2021
- E2E_OPENAI_MODEL=${E2E_OPENAI_MODEL:-gpt-4o-mini}
21-
# Azure
22-
- AZURE_API_KEY=${AZURE_API_KEY}
22+
# Azure Entra ID credentials (AZURE_API_KEY is passed via provider_data at request time)
23+
- TENANT_ID=${TENANT_ID:-}
24+
- CLIENT_ID=${CLIENT_ID:-}
25+
- CLIENT_SECRET=${CLIENT_SECRET:-}
2326
# RHAIIS
2427
- RHAIIS_URL=${RHAIIS_URL}
2528
- RHAIIS_API_KEY=${RHAIIS_API_KEY}
@@ -56,10 +59,13 @@ services:
5659
ports:
5760
- "8080:8080"
5861
volumes:
59-
- ./lightspeed-stack.yaml:/app-root/lightspeed-stack.yaml:Z
62+
- ./lightspeed-stack.yaml:/app-root/lightspeed-stack.yaml:z
6063
environment:
6164
- OPENAI_API_KEY=${OPENAI_API_KEY}
62-
- AZURE_API_KEY=${AZURE_API_KEY}
65+
# Azure Entra ID credentials (AZURE_API_KEY is obtained dynamically)
66+
- TENANT_ID=${TENANT_ID:-}
67+
- CLIENT_ID=${CLIENT_ID:-}
68+
- CLIENT_SECRET=${CLIENT_SECRET:-}
6369
depends_on:
6470
llama-stack:
6571
condition: service_healthy

0 commit comments

Comments
 (0)