-
-
Notifications
You must be signed in to change notification settings - Fork 868
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Azure DefaultAzureCredential() throwing exception during get_user_delegation_key() #1375
Comments
Forgot to add the exception: |
@tonybaloney do you have any ideas, you contributed a bunch of docs recently? In general, for Azure I'm relying on the community as I've never used it. |
I think it's because the code assumes you use SAS tokens and if you have an expiry it'll try and write a SAS token back to the connection object. Also the https://github.com/jschneier/django-storages/blob/master/storages/backends/azure_storage.py#L319-L331 Both of these should be fixed. I've got on my todo list this coming week to convert a Django template app to System Assigned Managed Identity using DefaultAzureCredential so I'll add this property ( @jschneier please feel free to tag me in any Azure issues like this. @andyp05 hope you don't mind waiting a couple of days for a fix, but I can't see an obvious workaround without modifying the code. |
Also @andyp05 just to check, what I'm assuming you're trying to do is:
|
Can you share the full settings? That would help me verify we're checking the same scenario Also, are your storage containers set to Private, Anonymous (Blob) or Anonymous (Container)? |
Which role have you assigned to the Managed Identity? User Delegation Key generation is a special role "Storage Blob Delegator" ( I'm looking at the error you're getting and it seems to be because your Managed Identity doesn't have that role (that's the most likely cause) |
I do have that role. Storing images to an ImageField works. The problem is when I try to view the image in a template using a form, the I created a template tag to create the SAS and that works fine as a workaround. The SAS is generating fine, so it is not an authorization issue. The relevant code looks like:
|
Ok, gotcha. I can't reproduce this but I'm going to configure a standalone template to try and reproduce it in another tenant. Here's the demo app I've written to test it https://github.com/tonybaloney/django-storages/blob/demo_stire/demo/app/templates/home.html#L9 I did notice that setting an expiry value is really important to the code flow and forcing it down the path of fetching a user delegation key: Here are all the storage account settings I've used https://github.com/tonybaloney/django-storages/blob/demo_stire/docs/backends/_resources/azure.bicep I'm testing this locally by using If you spot anything else different in those settings lmk |
I've tried a template with an edit form, a custom model with an image field and I still can't reproduce this error with the I've got a full E2E demo app that's compatible with AZD (Azure Developer CLI) here that has managed identity and the same settings for the storage containers we discussed. Everything works fine. https://github.com/tonybaloney/django-on-azure Without seeing specifics of your setup I'm stuck trying to figure out a proper fix or documentation on how to avoid this. I'd also like to add a test to the library to make sure nobody else hits this issue. I have office hours if you can email me at |
I think I found the issue. |
I found the existing issues opened on this. I had not put together the custom domain and the exception when I first reported the problem. As a workaround of the custom domain and proxy issue, I have implemented another settings variable called AZURE_URL_FOR_SAS for the purpose of getting the get_user_delegation_key and sas. However, I am returning the full URL with AZURE_CUSTOM_DOMAIN. This way, the user sees the custom domain and it is proxied by the CDN. Is this something that could be added to this package or am I missing something. |
1 similar comment
I found the existing issues opened on this. I had not put together the custom domain and the exception when I first reported the problem. As a workaround of the custom domain and proxy issue, I have implemented another settings variable called AZURE_URL_FOR_SAS for the purpose of getting the get_user_delegation_key and sas. However, I am returning the full URL with AZURE_CUSTOM_DOMAIN. This way, the user sees the custom domain and it is proxied by the CDN. Is this something that could be added to this package or am I missing something. |
Are you using Azure Front Door, Azure CDN or something else that requires the custom domain |
Was using Cloudflare as a proxy since all my domains are there. I tried turning off the proxy service (and with it all caching) and doing straight DNS and the problem remained. I am using a custom domain for consistency of the user interface when a user clicks on an image, I want them to see my url. Another benefit is I get caching and DDOS protections, I saw an issue where DNS providers convert HEAD calls to GET calls at the edge. Some say this is the problem. But turning off all Cloudflare performance and caching by not using the proxy should have disabled all conversions. Still did not work. Could a solution be that in I am doing this manually using template tags and it seems to work fine. |
We already have |
I must be missing something. I have It seems the code recognizes the custom domain and uses it in the call to You mention you already have methods to use |
|
Tested with a custom domain by deploying an Azure Frontdoor CDN profile: STORAGES = {
"default": {
"BACKEND": "storages.backends.azure_storage.AzureStorage",
"OPTIONS": {
"token_credential": DefaultAzureCredential(),
"account_name": "xxxxx",
"azure_container": "media",
"expiration_secs": 3600,
"custom_domain": "antdjangocdntest-xxx.b02.azurefd.net"
}
},
"staticfiles": {
"BACKEND": "storages.backends.azure_storage.AzureStorage",
"OPTIONS": {
"token_credential": DefaultAzureCredential(),
"account_name": "xxxxx",
"azure_container": "static",
"expiration_secs": 3600,
"custom_domain": "antdjangocdntest-xxx.b02.azurefd.net"
},
},
} Everything works as expected, including the |
Hi folks did we ever figure out what is going on here? |
Never got Using a custom domain:
I think the problem may be on the azure side and not in this package since I cannot manually generate a SAS with the custom domain. If I generate with the standard |
Just to add info: The following issue states that a SAS token cannot be generated using a custom URL. It is an old issue, but my experience is that it is still true. (Azure/azure-storage-node#437) If this is the case, we would need to store both URLs. The 'normal' Thanks |
per my earlier comments, we already have So if what you are saying is right then simply update |
@andyp05 can you verify if this would fix the issue for you. i think the patch we're looking at is diff --git a/storages/backends/azure_storage.py b/storages/backends/azure_storage.py
index 69b0213..c62c8f0 100644
--- a/storages/backends/azure_storage.py
+++ b/storages/backends/azure_storage.py
@@ -229,7 +229,7 @@ class AzureStorage(BaseStorage):
now = datetime.utcnow()
key_expiry_time = now + timedelta(days=7)
self._user_delegation_key = (
- self.custom_service_client.get_user_delegation_key(
+ self.service_client.get_user_delegation_key(
key_start_time=now, key_expiry_time=key_expiry_time
)
) |
Took a very quick look at this and I think it solves the get_user_delegation_key() exception problem. However, the custom domain is not being returned in the url. I will look at it more closely over the weekend. My quick thought is that the custom_domain is only needed for the formation of the url and not to get a custom client.
|
Yes, makes sense. Please test out and patch / report back. I am aiming to produce a release on Monday. |
I removed all references to custom client and added the code to reconstruct the url if a custom domain is set. This seems to resolve the issues I was experiencing, but I have not run unit tests on it. I am not that familiar with the code. I may have missed something big or small. I can save a new image, pull it back out, and get the URL in a template all with the custom domain used in all user facing html.
|
Ran some tests. Adding, editing, and deleting blobs seems to work fine. All links use the custom domain when displaying images in a template. No errors encountered. Thanks. |
If you are putting out a new release, You may want to replace utcnow() which is depreciated. Also, the datetime returned does not have a timezone set so it is naive. The code is already importing from |
Running Django 5.02, python 3.12.2 on Windows Server and IIS (hypercorn) and django-storages 1.14.2.
Have managed identity setup and working fine using DefaultAzureCredential() to get secrets in settings.py
Azure Storage using DefaultAzureCredential() manually to upload files not using django models is working fine.
However, django-storages is throwing an exception in get_user_delegation_key() when reading an ImageField from a model.
AZURE_CLIENT_ID environment variable is set to client id of managed identity. Also tried putting this in call to DefaultAzureCredential()
In settings.py:
The following IS working for Key Vault access:
It is not an DefaultAzureCredential(), Access Control, or Firewall issue since I can upload and read files from the app not using django models from another section of my code. Code snippet that works:
Any ideas would be appreciated.
Thanks
The text was updated successfully, but these errors were encountered: