I have an Azure Storage account that hosts a static web site as explained here. This means the static web site "lives" in a storage container named $web. This web site is accessible via a custom domain. This is currently working as desired. However, there is one file that I want to restrict access to.
There is one file in the $web storage container that I only want individuals to access if a) they have a key and b) it's during a specific time window. My thinking was that I could accomplish this with a Shared Access Signature (SAS). However, while testing this approach, it doesn't seem to work. It seems that everything in the $web storage container is publicly visible whether a SAS has been generated or not. Is this correct?
Is there a way to require that a file in the $web storage container have an SAS? Or, do I need to "host" the file in a separate storage container (thus removing it from my custom domain)?
Thank you.
When visit the files stored in $web container via primary static website endpoint(for example, https://contosoblobaccount.z22.web.core.windows.net/index.html), the files are always be accessible whether the container is public or private. So it doesn't matter the sas token is specified or not.
And the sas token only take effects if the $web container is private access, and people visit it via primary blob service endpoint(For example, https://contosoblobaccount.blob.core.windows.net/$web/index.html).
Please refer to this official doc for more details.
So for your purpose, you should put it in another container with private access.
Related
Situation:
We have a web-app on azure, and blob storage, via our web-app we write data into the blob, and currently read that data back out returning it as responses in the web-app.
What we're trying to do:
Trying to find a way to restrict access to the blob so that only our web-app can access it. Currently setting up an IP address in the firewall settings works fine if we have a static IP (we often test running the web app locally from our office and that lets us read/write to the blob just fine). However when we use the IP address of our web app (as read from the cross domain page of the web app) we do not get the same access, and get errors trying to read/write to the blob.
Question:
Is there a way to restrict access to the blob to the web app without having to set up a VPN on azure (too expensive)? I've seen people talk about using SAS to generate time valid links to blob content, and that makes sense for only allowing users to access content via our web-app (which would then deliver them the link), but that doesn't solve the problem of our web-app not being able to write to the blob when not publicly accessible.
Are we just trying to miss-use blobs? or is this a valid way to use them, but you have to do so via the VPN approach?
Another option would be to use Azure AD authentication combined with a managed identity on your App Service.
At the time of writing this feature is still in preview though.
I wrote on article on how to do this: https://joonasw.net/view/azure-ad-authentication-with-azure-storage-and-managed-service-identity.
The key parts:
Enable Managed Identity
Add the generated service principal the necessary role in the storage account/blob container
Change your code to use AAD access tokens acquired with the managed identity instead of access key/SAS token
Acquiring the token using https://www.nuget.org/packages/Microsoft.Azure.Services.AppAuthentication/1.1.0-preview:
private async Task<string> GetAccessTokenAsync()
{
var tokenProvider = new AzureServiceTokenProvider();
return await tokenProvider.GetAccessTokenAsync("https://storage.azure.com/");
}
Reading a blob using the token:
private async Task<Stream> GetBlobWithSdk(string accessToken)
{
var tokenCredential = new TokenCredential(accessToken);
var storageCredentials = new StorageCredentials(tokenCredential);
// Define the blob to read
var blob = new CloudBlockBlob(new Uri($"https://{StorageAccountName}.blob.core.windows.net/{ContainerName}/{FileName}"), storageCredentials);
// Open a data stream to the blob
return await blob.OpenReadAsync();
}
SAS Keys is the correct way to secure and grant access to your Blob Storage. Contrary to your belief, this will work with a private container. Here's a resource you may find helpful:
http://www.siddharthpandey.net/use-shared-access-signature-to-share-private-blob-in-azure/
Please also review Microsoft's guidelines on securing your Blob storage. This addresses many of the concerns you outline and is a must read for any Azure PaaS developer:
https://learn.microsoft.com/en-us/azure/storage/common/storage-security-guide
I am looking at using azure Containers and Blobs to store images and videos for my website. I found http://msdn.microsoft.com/en-us/library/windowsazure/dd179354.aspx which talks about the different ALC settings but it did not answer one of my questions. If a Container/Blob are set to "No public read access" the site says that only the account owner can read the data. Would this mean that people could not access it by the URL but my MVC Web App hosted on an Azure VM would be able to access it via URL?
Please bear with me if the answer sounds a bit preachy & unnecessary lengthy :)
Essentially each resource (Blob Container, Blob) in Windows Azure has a unique URL and is accessible via REST API (thus accessible over http/https protocol). Wit ACL, you basically tell storage service whether or not to honor the request sent to serve the resource. To read more about authentication mechanism, you may find this link useful: http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx.
When you set the ACL as No public read access, you're instructing storage service not to honor any anonymous requests. Only authenticated requests will be honored. To create an authenticated request, you would require your account name and key and create an authorization header which gets passed along with the request to access the request. If this authorization header is not present in your request, the request will be rejected.
So long story short, to answer your question even your MVC application won't be able to access the blob via URL unless that authorization header is included in the request. One possibility would be to explore Shared Access Signature (SAS) functionality in blob storage. This would give time-bound restricted permissions to blobs in your storage. So what you would do is create a SAS URL for your blob in your MVC app using your account name and key and use that SAS URL in the application.
To further explain the concept of ACL, let's say you have a blob container called mycontainer and it has a blob called myblob.txt in a storage account named myaccount. For listing blobs in the container, the container URL would be http://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=list and the blob URL would be http://myaccount.blob.core.windows.net/mycontainer/myblob.txt. Following will be the behavior when you try to access these URLs directly through the browser with different ACL:
No public read access
Container URL - Error
Blob URL - Error
Public read access for blobs only
Container URL - Error
Blob URL - Success (will download the blob)
Full public read access
Container URL - Success (will show an XML document containing information about all blobs in the container)
Blob URL - Success (will download the blob)
I have set a 'public' container where the blobs are stored as 'private', however irrespective of that I am still able to access the blobs directly with their URL within the container.
Any idea of why this is happening?
Thanks
I suspect that your browser or some other cache server is caching the file and you are not actually going to blob storage to get the file. You can use Fiddler or Netmon to validate what requests are being made to storage, or perhaps try a different machine or an in-private browsing session.
Once a blob container is marked private you cannot access any blob in that container without the private key or a signed request.
I upload my html5 games to Azure blobs here my list :
I changed games Container status as private and I tried to acess index.html with adding SAS policy to my container , I viewed my html file but I can't see any image or css because It depends on other files but can't allow to access.
I want to acess this game via only on my site so In my opinion ,When I set games container status as public and only index.html blob status private(I don't know Is it available on Azure Storage Explorer) , Can I access this game in my site with SAS ? I know It's a little strange issue but I try to solve it this way so Do you have any idea for accessing and opening this game only on my site ?
Thanks...
Unfortunately you can't do that because the access policy is applied at the blob container level and all blobs in that blob container inherit that policy. One possible solution would be to move css and images in a public container and keep the blobs you wish to keep private in this container only.
Thank you for your answer Gaurav, It's very helpful for solving problem , I tried it but It doesn't solve my problem because The main page try to find deployed container's directory :/ So I added "base href=.." into my html files and I provided redirect to other container files.Thank you so much all everything.
I have Azure Container created and set to Private. The permission must be set to Private because the content is only viewable to logged in user. However, I am intended to use the blob in tag. This is not possible when the Container is set to Private. Is there a way around this? Or have anybody else encounter the same problem?
All the code sample I have downloaded (PhluffyPhotos, MyPictures) from CodePlex / Code Project always set the container to Public (Container / Blob).
Thanks!
Consider using Shared Access Signatures. With these signatures, you can give your user temporary access to a Blob in a private container.
Eugenio Pace's article explains exactly what you're trying to do: Windows Azure Guidance – Using Shared Key Signatures for images in a-Expense
You can also set the container private and use your web app as a proxy to download file from the container then serve it via a handler.