Giter Site home page Giter Site logo

gsoft-inc / azure-cli-credentials-proxy Goto Github PK

View Code? Open in Web Editor NEW
25.0 25.0 7.0 68 KB

Azure CLI developer credential proxy for Docker, designed for use in local development environments.

License: Apache License 2.0

Dockerfile 33.28% C# 66.72%

azure-cli-credentials-proxy's People

Contributors

asimmon avatar heqianwang avatar infra-workleap avatar meziantou avatar princessmadmath avatar vad3245 avatar zav avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

azure-cli-credentials-proxy's Issues

Getting denied error despite valid PAT when pulling image with Docker pull

Describe the bug
I'm getting a denied error even though I created a token with read:packages scope. I can't pull the image.

To Reproduce
Steps to reproduce the behavior:
1 - Create PAT with read:packages scope.
2 - Run docker login using the PAT you created.
3 - Observe if you can log in successfully.
4 - Run docker pull ghcr.io/gsoft-inc/azure-cli-credentials-proxy:latest.
4 - Observe the "denied" error

Expected behavior
I should be able to see that the docker pull command works successfully with the pat I created.

ManagedIdentityCredential - Azure Arc MSI: To authenticate with Azure Arc MSI, status code 401 is expected on the first request

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Write an app using the JS SDK (the services I'm using are Azure OpenAI and Azure AI Search, both failed in the same way): https://learn.microsoft.com/en-us/javascript/api/overview/azure/identity-readme?view=azure-node-latest
  2. Build the app in docker, my compose file looks like
services:
  my-app:
    build: .
    depends_on:
      - azure-cli-proxy
    environment:
      - "IDENTITY_ENDPOINT=http://azure-cli-proxy:8080/token"
      - "IMDS_ENDPOINT=dummy_required_value"
  azure-cli-proxy:
    image: workleap/azure-cli-credentials-proxy:1.1.0
    ports:
      - "8080:8080"
    volumes:
      - "$HOME/.azure:/app/.azure/"
  1. Click on '....'
  2. See error
slack-help-bot-1   | /opt/app/node_modules/@azure/identity/dist/index.js:2747
slack-help-bot-1   |             throw new AuthenticationError(err.statusCode, {
slack-help-bot-1   |                   ^
slack-help-bot-1   |
slack-help-bot-1   | AuthenticationError: ManagedIdentityCredential authentication failed. Status code: 200
slack-help-bot-1   | More details:
slack-help-bot-1   | unknown_error Status code: 200
slack-help-bot-1   | More details:
slack-help-bot-1   | An unknown error has occurred. Response body:
slack-help-bot-1   |
slack-help-bot-1   | ManagedIdentityCredential - Azure Arc MSI: To authenticate with Azure Arc MSI, status code 401 is expected on the first request.  Response: {"access_token":"...", "expiresOn":"2024-07-24T16:25:17.0000000+00:00","expires_on":"1721838317","tokenType":"Bearer","resource":"https://cognitiveservices.azure.com"}
slack-help-bot-1   |     at LegacyMsiProvider.getToken (/opt/app/node_modules/@azure/identity/dist/index.js:2747:19)
slack-help-bot-1   |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
slack-help-bot-1   |     at async /opt/app/node_modules/@azure/identity/dist/index.js:3473:29
slack-help-bot-1   |     at async Object.withSpan (/opt/app/node_modules/@azure/core-tracing/dist/index.js:140:28)
slack-help-bot-1   |     at async DefaultAzureCredential.getToken (/opt/app/node_modules/@azure/identity/dist/index.js:3463:27)
slack-help-bot-1   |     at async tryGetAccessToken (/opt/app/node_modules/@azure/core-rest-pipeline/dist/index.js:1997:32)
slack-help-bot-1   |     at async beginRefresh (/opt/app/node_modules/@azure/core-rest-pipeline/dist/index.js:2005:17)
slack-help-bot-1   |     at async Object.defaultAuthorizeRequest [as authorizeRequest] (/opt/app/node_modules/@azure/core-rest-pipeline/dist/index.js:2128:25)
slack-help-bot-1   |     at async Object.sendRequest (/opt/app/node_modules/@azure/core-rest-pipeline/dist/index.js:2179:13)
slack-help-bot-1   |     at async AzureOpenAI.getRefreshedToken [as _azureADTokenProvider] (/opt/app/node_modules/@azure/identity/dist/index.js:4413:21)
slack-help-bot-1   |     at async AzureOpenAI._getAzureADToken (/opt/app/node_modules/openai/index.js:221:27)
slack-help-bot-1   |     at async AzureOpenAI.prepareOptions (/opt/app/node_modules/openai/index.js:236:23)
slack-help-bot-1   |     at async AzureOpenAI.makeRequest (/opt/app/node_modules/openai/core.js:285:9)
slack-help-bot-1   |     at async analyticsRecommendations (/opt/app/src/ai/ai.js:26:18)

Expected behavior

Documented option should work out of the box

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):

  • OS: Mac
  • Version: 1.1.0
  • azure/identity SDK: 4.40

Additional context

I also tried:

    environment:
      - "IDENTITY_ENDPOINT=http://azure-cli-proxy:8080/token"
      - "IMDS_ENDPOINT=dummy_required_value"
      - "MSI_ENDPOINT=http://azure-cli-proxy:8080/token"

After reading the source code of the Azure SDK and looking at what triggered each MSI type of lookup I removed IDENTITY_ENDPOINT and IMDS_ENDPOINT to have a file that looks like:

services:
  my-app:
    build: .
    depends_on:
      - azure-cli-proxy
    environment:
      - "MSI_ENDPOINT=http://azure-cli-proxy:8080/token"
  azure-cli-proxy:
    image: workleap/azure-cli-credentials-proxy:1.1.0
    ports:
      - "8080:8080"
    volumes:
      - "$HOME/.azure:/app/.azure/"
      #- "\\\\wsl$\\<DISTRONAME>\\home\\<USERNAME>\\.azure\\:/app/.azure/" # Uncomment on Windows with WSL

and that worked.

I'm not sure how generic across the SDKs the solution is but if it works across multiple then maybe just MSI_ENDPOINT should be specified?

My app just uses the Default Token credential that is recommended.

Issues using the proxy

Describe the bug
My containerized Python application gets the following error:

Attempted credentials:
2024-05-31 10:40:01     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 10:40:01 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 10:40:01     ManagedIdentityCredential: invalid literal for int() with base 10: '2024-05-31T09:49:50.0000000+00:00'
2024-05-31 10:40:01 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
2024-05-31 10:40:01 2024-05-31 08:40:01 - DefaultAzureCredential failed to retrieve a token from the included credentials.
2024-05-31 10:40:01 Attempted credentials:
2024-05-31 10:40:01     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 10:40:01 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 10:40:01     ManagedIdentityCredential: invalid literal for int() with base 10: '2024-05-31T09:49:50.0000000+00:00'
2024-05-31 10:40:01 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.

To Reproduce
Steps to reproduce the behavior:

I created the following docker-compose.yml to start the Azure CLI credentials proxy and my Docker container:

services:
  azclicredsproxy:
    image: workleap/azure-cli-credentials-proxy:latest
    volumes:
      - "/home/paolos/.azure:/app/.azure/"

  chat:
    depends_on:
      - azclicredsproxy
    image: chainlitchat:v1
    environment:
      - AZURE_OPENAI_BASE=https://paolosopenai.openai.azure.com/
      - AZURE_OPENAI_MODEL=gpt-35-turbo-16k
      - AZURE_OPENAI_DEPLOYMENT=gpt-35-turbo-16k
      - AZURE_OPENAI_API_VERSION=2024-02-15-preview
      - AZURE_OPENAI_TYPE=azure_ad
      - TEMPERATURE=0.9
      - IDENTITY_ENDPOINT=http://azclicredsproxy:8080/token
      - IMDS_ENDPOINT=random-placeholder
    ports:
      - "8000:8000"  

When I run the docker-compose up --detach, both containers start as expected. My chat app uses the following code to authenticate against Azure OpenAI:

# Create Token Provider
token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
)

# Configure OpenAI
openai = AsyncAzureOpenAI(
      api_version=api_version,
      azure_endpoint=api_base,
      azure_ad_token_provider=token_provider,
      max_retries=max_retries,
      timeout=timeout,
 )

If I look at the log of the azclicredsproxy container, I can see that the proxy call succeeds:

2024-05-31 10:38:55 08:38:55 info: Microsoft.Hosting.Lifetime[14] Now listening on: http://[::]:8080
2024-05-31 10:38:55 08:38:55 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down.
2024-05-31 10:38:55 08:38:55 info: Microsoft.Hosting.Lifetime[0] Hosting environment: Production
2024-05-31 10:38:55 08:38:55 info: Microsoft.Hosting.Lifetime[0] Content root path: /app
2024-05-31 10:40:00 08:40:00 info: Microsoft.AspNetCore.Hosting.Diagnostics[1] Request starting HTTP/1.1 GET http://azclicredsproxy:8080/token?api-version=2019-11-01&resource=https://cognitiveservices.azure.com - -
2024-05-31 10:40:00 08:40:00 info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] Executing endpoint 'HTTP: GET /token'
2024-05-31 10:40:01 08:40:01 info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] Executed endpoint 'HTTP: GET /token'
2024-05-31 10:40:01 08:40:01 info: Microsoft.AspNetCore.Hosting.Diagnostics[2] Request finished HTTP/1.1 GET http://azclicredsproxy:8080/token?api-version=2019-11-01&resource=https://cognitiveservices.azure.com - - - 200 - application/json;+charset=utf-8 735.7467ms

However, the chat application fails with the following error:

Attempted credentials:
2024-05-31 10:40:01     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 10:40:01 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 10:40:01     ManagedIdentityCredential: invalid literal for int() with base 10: '2024-05-31T09:49:50.0000000+00:00'
2024-05-31 10:40:01 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
2024-05-31 10:40:01 2024-05-31 08:40:01 - DefaultAzureCredential failed to retrieve a token from the included credentials.
2024-05-31 10:40:01 Attempted credentials:
2024-05-31 10:40:01     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 10:40:01 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 10:40:01     ManagedIdentityCredential: invalid literal for int() with base 10: '2024-05-31T09:49:50.0000000+00:00'
2024-05-31 10:40:01 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.

If I run the following command inside the proxy container:

wget --no-check-certificate -qO- "http://azclicredsproxy:8080/token?api-version=2019-11-01&resource=https://cognitiveservices.azure.com" > output.txt

The call successfully completes and returns a valid JWT, but there might be a problem with the expires_on format:

  • The expires_on returned by the proxy has the following format 2024-05-31T15:34:45.0000000+00:00
  • The expires_on returned by an az account get-access-token is a number, e.g. 1717170534 in epoch format.

I changed the Program.cs as follows:

using System.Globalization;
using Azure.Core;
using Azure.Identity;

var tokenCredential = new AzureCliCredential();
var app = WebApplication.CreateBuilder(args).Build();

// Can be consumed by ManagedIdentityCredential by specifying IDENTITY_ENDPOINT and IMDS_ENDPOINT environment variables to this action URL
// See https://github.com/Azure/azure-sdk-for-net/blob/Azure.Identity_1.8.0/sdk/identity/Azure.Identity/src/AzureArcManagedIdentitySource.cs
app.MapGet("/token", async (string resource) =>
{
    var token = await tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { resource }));
    return new Dictionary<string, string> { ["access_token"] = token.Token, ["expiresOn"] = token.ExpiresOn.ToString("O", CultureInfo.InvariantCulture), ["expires_on"] = token.ExpiresOn.ToUnixTimeSeconds().ToString() };
});

app.Run();

Now, I get another exception:

2024-05-31 15:20:42 - DefaultAzureCredential failed to retrieve a token from the included credentials.
2024-05-31 17:20:42 Attempted credentials:
2024-05-31 17:20:42     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 17:20:42 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 17:20:42     ManagedIdentityCredential: 'resource'
2024-05-31 17:20:42 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
2024-05-31 17:20:42 2024-05-31 15:20:42 - DefaultAzureCredential failed to retrieve a token from the included credentials.
2024-05-31 17:20:42 Attempted credentials:
2024-05-31 17:20:42     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 17:20:42 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 17:20:42     ManagedIdentityCredential: 'resource'
2024-05-31 17:20:42 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.
2024-05-31 17:20:42 Traceback (most recent call last):
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/chainlit/utils.py", line 39, in wrapper
2024-05-31 17:20:42     return await user_function(**params_values)
2024-05-31 17:20:42            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/app/chat.py", line 90, in on_message
2024-05-31 17:20:42     async for stream_resp in await openai.chat.completions.create(
2024-05-31 17:20:42                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/openai/resources/chat/completions.py", line 1211, in create
2024-05-31 17:20:42     return await self._post(
2024-05-31 17:20:42            ^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/openai/_base_client.py", line 1536, in post
2024-05-31 17:20:42     return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
2024-05-31 17:20:42            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/openai/_base_client.py", line 1315, in request
2024-05-31 17:20:42     return await self._request(
2024-05-31 17:20:42            ^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/openai/_base_client.py", line 1332, in _request
2024-05-31 17:20:42     await self._prepare_options(options)
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/openai/lib/azure.py", line 517, in _prepare_options
2024-05-31 17:20:42     azure_ad_token = await self._get_azure_ad_token()
2024-05-31 17:20:42                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/openai/lib/azure.py", line 501, in _get_azure_ad_token
2024-05-31 17:20:42     token = provider()
2024-05-31 17:20:42             ^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/azure/identity/_bearer_token_provider.py", line 43, in wrapper
2024-05-31 17:20:42     policy.on_request(request)
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/azure/core/pipeline/policies/_authentication.py", line 99, in on_request
2024-05-31 17:20:42     self._token = self._credential.get_token(*self._scopes)
2024-05-31 17:20:42                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/azure/identity/_credentials/default.py", line 225, in get_token
2024-05-31 17:20:42     token = super().get_token(*scopes, claims=claims, tenant_id=tenant_id, **kwargs)
2024-05-31 17:20:42             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-05-31 17:20:42   File "/opt/venv/lib/python3.11/site-packages/azure/identity/_credentials/chained.py", line 124, in get_token
2024-05-31 17:20:42     raise ClientAuthenticationError(message=message)
2024-05-31 17:20:42 azure.core.exceptions.ClientAuthenticationError: DefaultAzureCredential failed to retrieve a token from the included credentials.
2024-05-31 17:20:42 Attempted credentials:
2024-05-31 17:20:42     EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
2024-05-31 17:20:42 Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
2024-05-31 17:20:42     ManagedIdentityCredential: 'resource'
2024-05-31 17:20:42 To mitigate this issue, please refer to the troubleshooting guidelines here at https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):

  • OS: WSL2 on Windows 11
  • Version: 11
  • IDE: Visual Studio Code

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.