├── .devcontainer
└── devcontainer.json
├── .env.sample
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── SECURITY.md
├── dependabot.yaml
└── workflows
│ ├── azure-dev.yaml
│ └── template-validation.yaml
├── .gitignore
├── LICENSE
├── README.md
├── azure.yaml
├── diagram.png
├── example.py
├── infra
├── main.bicep
└── main.parameters.json
├── requirements.txt
├── write_dot_env.ps1
└── write_dot_env.sh
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "azure-openai-keyless",
3 | "image": "mcr.microsoft.com/devcontainers/python:3.12-bullseye",
4 | "features": {
5 | "ghcr.io/azure/azure-dev/azd:latest": {}
6 | },
7 | "customizations": {
8 | "vscode": {
9 | "extensions": [
10 | "ms-azuretools.azure-dev",
11 | "ms-azuretools.vscode-bicep"
12 | ]
13 | }
14 | },
15 | "postCreateCommand": "",
16 | "remoteUser": "vscode",
17 | "hostRequirements": {
18 | "memory": "8gb"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.env.sample:
--------------------------------------------------------------------------------
1 | AZURE_OPENAI_GPT_DEPLOYMENT=
2 | AZURE_OPENAI_SERVICE=
3 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to azure-openai-keyless-python
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
4 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
5 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
6 |
7 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
8 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
9 | provided by the bot. You will only need to do this once across all repos using our CLA.
10 |
11 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
12 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
13 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
14 |
15 | - [Code of Conduct](#coc)
16 | - [Issues and Bugs](#issue)
17 | - [Feature Requests](#feature)
18 | - [Submission Guidelines](#submit)
19 |
20 | ## Code of Conduct
21 | Help us keep this project open and inclusive. Please read and follow our [Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
22 |
23 | ## Found an Issue?
24 | If you find a bug in the source code or a mistake in the documentation, you can help us by
25 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can
26 | [submit a Pull Request](#submit-pr) with a fix.
27 |
28 | ## Want a Feature?
29 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub
30 | Repository. If you would like to *implement* a new feature, please submit an issue with
31 | a proposal for your work first, to be sure that we can use it.
32 |
33 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
34 |
35 | ## Submission Guidelines
36 |
37 | ### Submitting an Issue
38 | Before you submit an issue, search the archive, maybe your question was already answered.
39 |
40 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
41 | Help us to maximize the effort we can spend fixing issues and adding new
42 | features, by not reporting duplicate issues. Providing the following information will increase the
43 | chances of your issue being dealt with quickly:
44 |
45 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
46 | * **Version** - what version is affected (e.g. 0.1.2)
47 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
48 | * **Browsers and Operating System** - is this a problem with all browsers?
49 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps
50 | * **Related Issues** - has a similar issue been reported before?
51 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
52 | causing the problem (line of code or commit)
53 |
54 | You can file new issues by providing the above information at the corresponding repository's issues link: https://github.com/Azure-samples/azure-openai-keyless-python/issues/new].
55 |
56 | ### Submitting a Pull Request (PR)
57 | Before you submit your Pull Request (PR) consider the following guidelines:
58 |
59 | * Search the repository (https://github.com/Azure-samples/azure-openai-keyless-python/pulls) for an open or closed PR
60 | that relates to your submission. You don't want to duplicate effort.
61 |
62 | * Make your changes in a new git fork:
63 |
64 | * Commit your changes using a descriptive commit message
65 | * Push your fork to GitHub:
66 | * In GitHub, create a pull request
67 | * If we suggest changes then:
68 | * Make the required updates.
69 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
70 |
71 | ```shell
72 | git rebase master -i
73 | git push -f
74 | ```
75 |
76 | That's it! Thank you for your contribution!
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 | > Please provide us with the following information:
5 | > ---------------------------------------------------------------
6 |
7 | ### This issue is for a: (mark with an `x`)
8 | ```
9 | - [ ] bug report -> please search issues before submitting
10 | - [ ] feature request
11 | - [ ] documentation issue or request
12 | - [ ] regression (a behavior that used to work and stopped in a new release)
13 | ```
14 |
15 | ### Minimal steps to reproduce
16 | >
17 |
18 | ### Any log messages given by the failure
19 | >
20 |
21 | ### Expected/desired behavior
22 | >
23 |
24 | ### OS and Version?
25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?)
26 |
27 | ### Versions
28 | >
29 |
30 | ### Mention any other details that might be useful
31 |
32 | > ---------------------------------------------------------------
33 | > Thanks! We'll be in touch soon.
34 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security
2 |
3 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
4 |
5 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](), please report it to us as described below.
6 |
7 | ## Reporting Security Issues
8 |
9 | **Please do not report security vulnerabilities through public GitHub issues.**
10 |
11 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
12 |
13 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/msrc/pgp-key-msrc).
14 |
15 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
16 |
17 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
18 |
19 | - Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
20 | - Full paths of source file(s) related to the manifestation of the issue
21 | - The location of the affected source code (tag/branch/commit or direct URL)
22 | - Any special configuration required to reproduce the issue
23 | - Step-by-step instructions to reproduce the issue
24 | - Proof-of-concept or exploit code (if possible)
25 | - Impact of the issue, including how an attacker might exploit the issue
26 |
27 | This information will help us triage your report more quickly.
28 |
29 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
30 |
31 | ## Preferred Languages
32 |
33 | We prefer all communications to be in English.
34 |
35 | ## Policy
36 |
37 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/msrc/cvd).
38 |
--------------------------------------------------------------------------------
/.github/dependabot.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |
4 | # Maintain dependencies for GitHub Actions
5 | - package-ecosystem: "github-actions"
6 | directory: "/"
7 | schedule:
8 | interval: "weekly"
9 | groups:
10 | github-actions:
11 | patterns:
12 | - "*"
13 |
--------------------------------------------------------------------------------
/.github/workflows/azure-dev.yaml:
--------------------------------------------------------------------------------
1 | name: Provision with azd
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | # Run when commits are pushed to mainline branch (main or master)
7 | # Set this to the mainline branch you are using
8 | branches:
9 | - main
10 |
11 | # GitHub Actions workflow to deploy to Azure using azd
12 | # To configure required secrets for connecting to Azure, simply run `azd pipeline config`
13 |
14 | # Set up permissions for deploying with secretless Azure federated credentials
15 | # https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Clinux#set-up-azure-login-with-openid-connect-authentication
16 | permissions:
17 | id-token: write
18 | contents: read
19 |
20 | jobs:
21 | build:
22 | runs-on: ubuntu-latest
23 | env:
24 | # azd required
25 | AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
26 | AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
27 | AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
28 | AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
29 | AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v4
33 |
34 | - name: Install azd
35 | uses: Azure/setup-azd@v2.1.0
36 |
37 | - name: Install Nodejs
38 | uses: actions/setup-node@v4
39 | with:
40 | node-version: 18
41 |
42 | - name: Log in with Azure (Federated Credentials)
43 | if: ${{ env.AZURE_CLIENT_ID != '' }}
44 | run: |
45 | azd auth login `
46 | --client-id "$Env:AZURE_CLIENT_ID" `
47 | --federated-credential-provider "github" `
48 | --tenant-id "$Env:AZURE_TENANT_ID"
49 | shell: pwsh
50 |
51 | - name: Provision Infrastructure
52 | run: azd provision --no-prompt
53 | env:
54 | AZD_INITIAL_ENVIRONMENT_CONFIG: ${{ secrets.AZD_INITIAL_ENVIRONMENT_CONFIG }}
55 | AZURE_SERVER_APP_SECRET: ${{ secrets.AZURE_SERVER_APP_SECRET }}
56 | AZURE_CLIENT_APP_SECRET: ${{ secrets.AZURE_CLIENT_APP_SECRET }}
57 |
--------------------------------------------------------------------------------
/.github/workflows/template-validation.yaml:
--------------------------------------------------------------------------------
1 | # This is for internal use to make sure our samples follow best practices. You can delete this in your fork.
2 | name: Template validation sample workflow
3 | on:
4 | workflow_dispatch:
5 |
6 | permissions:
7 | contents: read
8 | id-token: write
9 | pull-requests: write
10 |
11 | jobs:
12 | template_validation_job:
13 | runs-on: ubuntu-latest
14 | name: template validation
15 | steps:
16 | - uses: actions/checkout@v4
17 |
18 | - uses: microsoft/template-validation-action@v0.4.1
19 | env:
20 | AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
21 | AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
22 | AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
23 | AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
24 | AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 |
27 | - name: print result
28 | run: cat ${{ steps.validation.outputs.resultFile }}
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Azure az webapp deployment details
2 | .azure
3 | *_env
4 |
5 | # Byte-compiled / optimized / DLL files
6 | __pycache__/
7 | *.py[cod]
8 | *$py.class
9 |
10 | # C extensions
11 | *.so
12 |
13 | # Distribution / packaging
14 | .Python
15 | build/
16 | develop-eggs/
17 | dist/
18 | downloads/
19 | eggs/
20 | .eggs/
21 | lib/
22 | lib64/
23 | parts/
24 | sdist/
25 | var/
26 | wheels/
27 | share/python-wheels/
28 | *.egg-info/
29 | .installed.cfg
30 | *.egg
31 | MANIFEST
32 |
33 | # PyInstaller
34 | # Usually these files are written by a python script from a template
35 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
36 | *.manifest
37 | *.spec
38 |
39 | # Installer logs
40 | pip-log.txt
41 | pip-delete-this-directory.txt
42 |
43 | # Unit test / coverage reports
44 | htmlcov/
45 | .tox/
46 | .nox/
47 | .coverage
48 | .coverage.*
49 | .cache
50 | nosetests.xml
51 | coverage.xml
52 | *.cover
53 | *.py,cover
54 | .hypothesis/
55 | .pytest_cache/
56 | cover/
57 |
58 | # Translations
59 | *.mo
60 | *.pot
61 |
62 | # Django stuff:
63 | *.log
64 | local_settings.py
65 | db.sqlite3
66 | db.sqlite3-journal
67 |
68 | # Flask stuff:
69 | instance/
70 | .webassets-cache
71 |
72 | # Scrapy stuff:
73 | .scrapy
74 |
75 | # Sphinx documentation
76 | docs/_build/
77 |
78 | # PyBuilder
79 | .pybuilder/
80 | target/
81 |
82 | # Jupyter Notebook
83 | .ipynb_checkpoints
84 |
85 | # IPython
86 | profile_default/
87 | ipython_config.py
88 |
89 | # pyenv
90 | # For a library or package, you might want to ignore these files since the code is
91 | # intended to run in multiple environments; otherwise, check them in:
92 | # .python-version
93 |
94 | # pipenv
95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
98 | # install all needed dependencies.
99 | #Pipfile.lock
100 |
101 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
102 | __pypackages__/
103 |
104 | # Celery stuff
105 | celerybeat-schedule
106 | celerybeat.pid
107 |
108 | # SageMath parsed files
109 | *.sage.py
110 |
111 | # Environments
112 | .env
113 | .venv
114 | env/
115 | venv/
116 | ENV/
117 | env.bak/
118 | venv.bak/
119 |
120 | # Spyder project settings
121 | .spyderproject
122 | .spyproject
123 |
124 | # Rope project settings
125 | .ropeproject
126 |
127 | # mkdocs documentation
128 | /site
129 |
130 | # mypy
131 | .mypy_cache/
132 | .dmypy.json
133 | dmypy.json
134 |
135 | # Pyre type checker
136 | .pyre/
137 |
138 | # pytype static type analyzer
139 | .pytype/
140 |
141 | # Cython debug symbols
142 | cython_debug/
143 |
144 | # NPM
145 | npm-debug.log*
146 | node_modules
147 | static/
148 |
149 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Azure Samples
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
16 | # Azure OpenAI resource with keyless auth (Python)
17 |
18 | [](https://github.com/codespaces/new?hide_repo_select=true&ref=main&skip_quickstart=true&machine=basicLinux32gb&repo=784926917&devcontainer_path=.devcontainer%2Fdevcontainer.json&geo=WestUs2)
19 | [](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/Azure-Samples/azure-openai-keyless-python)
20 |
21 | The purpose of this repository is to provision an Azure OpenAI account with an RBAC role permission for your user account to access,
22 | so that you can use the OpenAI API SDKs with keyless (Entra) authentication.
23 |
24 | * [Features](#features)
25 | * [Getting started](#getting-started)
26 | * [GitHub Codespaces](#github-codespaces)
27 | * [VS Code Dev Containers](#vs-code-dev-containers)
28 | * [Local environment](#local-environment)
29 | * [Deployment](#deployment)
30 | * [Running the Python example](#running-the-python-example)
31 | * [Guidance](#guidance)
32 | * [Costs](#costs)
33 | * [Security guidelines](#security-guidelines)
34 | * [Resources](#resources)
35 |
36 | ## Features
37 |
38 | * Provisions an Azure OpenAI account with keyless authentication enabled
39 | * Grants the "Cognitive Services OpenAI User" RBAC role to your user account
40 | * Deploys a gpt-4o-mini model by default, but you can modify the [Bicep template](infra/main.bicep) to deploy other models
41 | * Example script uses the [openai](https://pypi.org/project/openai/) Python package to make a request to the Azure OpenAI API
42 |
43 | ### Architecture diagram
44 |
45 | 
46 |
47 | ## Getting started
48 |
49 | You have a few options for getting started with this template.
50 | The quickest way to get started is GitHub Codespaces, since it will setup all the tools for you, but you can also [set it up locally](#local-environment).
51 |
52 | ### GitHub Codespaces
53 |
54 | You can run this template virtually by using GitHub Codespaces. The button will open a web-based VS Code instance in your browser:
55 |
56 | 1. Open the template (this may take several minutes):
57 |
58 | [](https://codespaces.new/Azure-Samples/azure-openai-keyless-python)
59 |
60 | 2. Open a terminal window
61 | 3. Continue with the [deployment steps](#deployment)
62 |
63 | ### VS Code Dev Containers
64 |
65 | A related option is VS Code Dev Containers, which will open the project in your local VS Code using the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers):
66 |
67 | 1. Start Docker Desktop (install it if not already installed)
68 | 2. Open the project:
69 |
70 | [](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/azure-samples/azure-openai-keyless-python)
71 |
72 | 3. In the VS Code window that opens, once the project files show up (this may take several minutes), open a terminal window.
73 | 4. Continue with the [deployment steps](#deployment)
74 |
75 | ### Local environment
76 |
77 | 1. Make sure the following tools are installed:
78 |
79 | * [Azure Developer CLI (azd)](https://aka.ms/install-azd)
80 | * [Python 3.9+](https://www.python.org/downloads/)
81 |
82 | 2. Make a new directory called `azure-openai-keyless-python` and clone this template into it using the `azd` CLI:
83 |
84 | ```shell
85 | azd init -t azure-openai-keyless-python
86 | ```
87 |
88 | You can also use git to clone the repository if you prefer.
89 |
90 | 3. Continue with the [deployment steps](#deployment)
91 |
92 | ## Deployment
93 |
94 | 1. Login to Azure:
95 |
96 | ```shell
97 | azd auth login
98 | ```
99 |
100 | For GitHub Codespaces users, if the previous command fails, try:
101 |
102 | ```shell
103 | azd auth login --use-device-code
104 | ```
105 |
106 | 2. Provision the OpenAI account:
107 |
108 | ```shell
109 | azd provision
110 | ```
111 |
112 | It will prompt you to provide an `azd` environment name (like "chat-app"), select a subscription from your Azure account, and select a [location where the OpenAI model is available](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#standard-deployment-model-availability) (like "canadaeast"). Then it will provision the resources in your account and deploy the latest code.
113 |
114 | ⚠️ If you get an error or timeout with deployment, changing the location can help, as there may be availability constraints for the OpenAI resource. To change the location run:
115 |
116 | ```shell
117 | azd env set AZURE_LOCATION "yournewlocationname"
118 | ```
119 |
120 | 3. When `azd` has finished, you should have an OpenAI account you can use locally when logged into your Azure account. You can output the necessary environment variables into an `.env` file by running a script:
121 |
122 | For Mac OS X / Linux:
123 |
124 | ```shell
125 | ./write_dot_env.sh
126 | ```
127 |
128 | For Windows:
129 |
130 | ```shell
131 | pwsh ./write_dot_env.ps1
132 | ```
133 |
134 | 4. Then you can proceed to [run the Python example](#running-the-python-example).
135 |
136 | ## Running the Python example
137 |
138 | 1. If you're not already running in a Codespace or Dev Container, create a Python virtual environment.
139 |
140 | 2. Install the requirements:
141 |
142 | ```shell
143 | python -m pip install -r requirements.txt
144 | ```
145 |
146 | 3. Run the example:
147 |
148 | ```shell
149 | python example.py
150 | ```
151 |
152 | This will use the OpenAI API SDK to make a request to the OpenAI API and print the response.
153 |
154 | ## Guidance
155 |
156 | ### Costs
157 |
158 | This template creates only the Azure OpenAI resource, which is free to provision. However, you will be charged for the usage of the Azure OpenAI chat completions API. The pricing is based on the number of tokens used, with around 1-3 tokens used per word. You can find the pricing details for the OpenAI API on the [Azure Cognitive Services pricing page](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/).
159 |
160 | ### Security guidelines
161 |
162 | This template uses [keyless authentication](https://learn.microsoft.com/en-us/azure/developer/ai/keyless-connections) for authenticating to the Azure OpenAI resource. This is a secure way to authenticate to Azure resources without needing to store credentials in your code. Your Azure user account is assigned the "Cognitive Services OpenAI User" role, which allows you to access the OpenAI resource. You can find more information about the permissions of this role in the [Azure OpenAI documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/role-based-access-control).
163 |
164 | For further security, you could also deploy the Azure OpenAI inside a private virtual network (VNet) and use a private endpoint to access it. This would prevent the OpenAI resource from being accessed from the public internet.
165 |
166 | ## Resources
167 |
168 | * [Video: Using keyless auth with Azure AI services](https://www.youtube.com/watch?v=IkDcQvKoQ8k)
169 | * [Sample app: Azure OpenAI + Container Apps + Managed Identity](https://github.com/Azure-Samples/openai-chat-app-quickstart)
170 |
--------------------------------------------------------------------------------
/azure.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2 |
3 | name: azure-openai-keyless-python
4 | metadata:
5 | template: azure-openai-keyless-python@0.0.4
6 |
--------------------------------------------------------------------------------
/diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Azure-Samples/azure-openai-keyless-python/2eba23bddf6424efbc1e365419885816701a729a/diagram.png
--------------------------------------------------------------------------------
/example.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 |
4 | import azure.identity
5 | import openai
6 | from dotenv import load_dotenv
7 |
8 | load_dotenv()
9 | # Change to logging.DEBUG for more verbose logging from Azure and OpenAI SDKs
10 | logging.basicConfig(level=logging.WARNING)
11 |
12 |
13 | if not os.getenv("AZURE_OPENAI_SERVICE") or not os.getenv("AZURE_OPENAI_GPT_DEPLOYMENT"):
14 | logging.warning("AZURE_OPENAI_SERVICE and AZURE_OPENAI_GPT_DEPLOYMENT environment variables are empty. See README.")
15 | exit(1)
16 |
17 |
18 | credential = azure.identity.DefaultAzureCredential()
19 | token_provider = azure.identity.get_bearer_token_provider(credential, "https://cognitiveservices.azure.com/.default")
20 |
21 | client = openai.AzureOpenAI(
22 | api_version="2024-03-01-preview",
23 | azure_endpoint=f"https://{os.getenv('AZURE_OPENAI_SERVICE')}.openai.azure.com",
24 | azure_ad_token_provider=token_provider,
25 | )
26 |
27 | response = client.chat.completions.create(
28 | # For Azure OpenAI, the model parameter must be set to the deployment name
29 | model=os.getenv("AZURE_OPENAI_GPT_DEPLOYMENT"),
30 | temperature=0.7,
31 | n=1,
32 | messages=[
33 | {"role": "system", "content": "You are a helpful assistant that makes lots of cat references and uses emojis."},
34 | {"role": "user", "content": "Write a haiku about a hungry cat who wants tuna"},
35 | ],
36 | )
37 |
38 | print("Response: ")
39 | print(response.choices[0].message.content)
40 |
--------------------------------------------------------------------------------
/infra/main.bicep:
--------------------------------------------------------------------------------
1 | targetScope = 'subscription'
2 |
3 | @minLength(1)
4 | @maxLength(64)
5 | @description('Name of the the environment which is used to generate a short unique hash used in all resources.')
6 | param environmentName string
7 |
8 | @minLength(1)
9 | @description('Location for the OpenAI resource')
10 | // https://learn.microsoft.com/azure/ai-services/openai/concepts/models?tabs=python-secure%2Cglobal-standard%2Cstandard-chat-completions#models-by-deployment-type
11 | @allowed([
12 | 'australiaeast'
13 | 'brazilsouth'
14 | 'canadaeast'
15 | 'eastus'
16 | 'eastus2'
17 | 'francecentral'
18 | 'germanywestcentral'
19 | 'japaneast'
20 | 'koreacentral'
21 | 'northcentralus'
22 | 'norwayeast'
23 | 'polandcentral'
24 | 'southafricanorth'
25 | 'southcentralus'
26 | 'southindia'
27 | 'spaincentral'
28 | 'swedencentral'
29 | 'switzerlandnorth'
30 | 'uksouth'
31 | 'westeurope'
32 | 'westus'
33 | 'westus3'
34 | ])
35 | @metadata({
36 | azd: {
37 | type: 'location'
38 | }
39 | })
40 | param location string
41 |
42 | @description('Name of the GPT model to deploy')
43 | param gptModelName string = 'gpt-4o-mini'
44 |
45 | @description('Version of the GPT model to deploy')
46 | // See version availability in this table:
47 | // https://learn.microsoft.com/azure/ai-services/openai/concepts/models?tabs=python-secure%2Cglobal-standard%2Cstandard-chat-completions#models-by-deployment-type
48 | param gptModelVersion string = '2024-07-18'
49 |
50 | @description('Name of the model deployment (can be different from the model name)')
51 | param gptDeploymentName string = 'gpt-4o-mini'
52 |
53 | @description('Capacity of the GPT deployment')
54 | // You can increase this, but capacity is limited per model/region, so you will get errors if you go over
55 | // https://learn.microsoft.com/en-us/azure/ai-services/openai/quotas-limits
56 | param gptDeploymentCapacity int = 30
57 |
58 | @description('Id of the user or app to assign application roles')
59 | param principalId string = ''
60 |
61 | @description('Non-empty if the deployment is running on GitHub Actions')
62 | param runningOnGitHub string = ''
63 |
64 | var principalType = empty(runningOnGitHub) ? 'User' : 'ServicePrincipal'
65 |
66 | var resourceToken = toLower(uniqueString(subscription().id, environmentName, location))
67 | var prefix = '${environmentName}${resourceToken}'
68 | var tags = { 'azd-env-name': environmentName }
69 |
70 | // Organize resources in a resource group
71 | resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
72 | name: '${prefix}-rg'
73 | location: location
74 | tags: tags
75 | }
76 |
77 | var openAiServiceName = '${prefix}-openai'
78 | module openAi 'br/public:avm/res/cognitive-services/account:0.7.1' = {
79 | name: 'openai'
80 | scope: resourceGroup
81 | params: {
82 | name: openAiServiceName
83 | location: location
84 | tags: tags
85 | kind: 'OpenAI'
86 | sku: 'S0'
87 | customSubDomainName: openAiServiceName
88 | networkAcls: {
89 | defaultAction: 'Allow'
90 | bypass: 'AzureServices'
91 | }
92 | deployments: [
93 | {
94 | name: gptDeploymentName
95 | model: {
96 | format: 'OpenAI'
97 | name: gptModelName
98 | version: gptModelVersion
99 | }
100 | sku: {
101 | name: 'GlobalStandard'
102 | capacity: gptDeploymentCapacity
103 | }
104 | }
105 | ]
106 | roleAssignments: [
107 | {
108 | principalId: principalId
109 | roleDefinitionIdOrName: 'Cognitive Services OpenAI User'
110 | principalType: principalType
111 | }
112 | ]
113 | }
114 | }
115 |
116 | output AZURE_LOCATION string = location
117 | output AZURE_TENANT_ID string = tenant().tenantId
118 | output AZURE_RESOURCE_GROUP string = resourceGroup.name
119 |
120 | // Specific to Azure OpenAI
121 | output AZURE_OPENAI_SERVICE string = openAi.outputs.name
122 | output AZURE_OPENAI_GPT_MODEL string = gptModelName
123 | output AZURE_OPENAI_GPT_DEPLOYMENT string = gptDeploymentName
124 |
--------------------------------------------------------------------------------
/infra/main.parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
3 | "contentVersion": "1.0.0.0",
4 | "parameters": {
5 | "environmentName": {
6 | "value": "${AZURE_ENV_NAME}"
7 | },
8 | "location": {
9 | "value": "${AZURE_LOCATION}"
10 | },
11 | "principalId": {
12 | "value": "${AZURE_PRINCIPAL_ID}"
13 | },
14 | "runningOnGitHub": {
15 | "value": "${GITHUB_ACTIONS}"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | azure-identity
2 | openai
3 | python-dotenv
--------------------------------------------------------------------------------
/write_dot_env.ps1:
--------------------------------------------------------------------------------
1 | # Clear the contents of the .env file
2 | Set-Content -Path .env -Value ""
3 |
4 | # Append new values to the .env file
5 | $azureOpenAiDeployment = azd env get-value AZURE_OPENAI_GPT_DEPLOYMENT
6 | $azureOpenAiService = azd env get-value AZURE_OPENAI_SERVICE
7 |
8 | Add-Content -Path .env -Value "AZURE_OPENAI_GPT_DEPLOYMENT=$azureOpenAiDeployment"
9 | Add-Content -Path .env -Value "AZURE_OPENAI_SERVICE=$azureOpenAiService"
10 |
--------------------------------------------------------------------------------
/write_dot_env.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Clear the contents of the .env file
4 | > .env
5 |
6 | # Append new values to the .env file
7 | echo "AZURE_OPENAI_GPT_DEPLOYMENT=$(azd env get-value AZURE_OPENAI_GPT_DEPLOYMENT)" >> .env
8 | echo "AZURE_OPENAI_SERVICE=$(azd env get-value AZURE_OPENAI_SERVICE)" >> .env
9 |
--------------------------------------------------------------------------------