azureazure-web-app-serviceazure-storage-accountvnet

GetBlob request is failing, when PutBlob and ListBlob are successfull


I configured vNet integration for my python application and also configured service endpoint for storageaccount (vNet firewall also enabled). Put and List requests are successful, but GetBlob is failing and I am unable to view image in my test application:

2.0;2024-07-11T11:32:44.8196257Z;ListBlobs;Success;200;9;6;authenticated;storagecasbx01we;storagecasbx01we;blob;"https:///<endpoint>.blob.core.windows.net:443/cp-images?restype=container&amp;comp=list";"/<endpoint>/cp-images";67d5b517-701e-002a-5086-d3f759000000;0;10.0.0.254:52420;2020-06-12;575;0;220;2956;0;;;;;;"azsdk-python-storage-blob/12.8.1 Python/3.12.2 (Linux-5.15.153.1-2.cm2-x86_64-with-glibc2.31)";;"4a9a9e1e-3f79-11ef-b188-a665be233668";;;;;;;;
2.0;2024-07-11T11:32:51.9590052Z;PutBlob;BlobAlreadyExists;409;5;5;authenticated;storagecasbx01we;storagecasbx01we;blob;"https://<endpoint>.blob.core.windows.net:443/cp-images/NewSmall.png";"/<endpoint>/cp-images/NewSmall.png";67d5cab5-701e-002a-5f86-d3f759000000;0;10.0.0.254:52420;2020-06-12;659;3966;235;220;3966;;"FUj7LV1B0HHctq3t5gmWCA==";;;"If-None-Match=*";"azsdk-python-storage-blob/12.8.1 Python/3.12.2 (Linux-5.15.153.1-2.cm2-x86_64-with-glibc2.31)";;"4eeaa860-3f79-11ef-b188-a665be233668";;;;;;;;
2.0;2024-07-11T11:32:52.1686959Z;ListBlobs;Success;200;6;3;authenticated;storagecasbx01we;storagecasbx01we;blob;"https:///<endpoint>.blob.core.windows.net:443/cp-images?restype=container&amp;comp=list";"/<endpoint>/cp-images";67d5cb4f-701e-002a-6786-d3f759000000;0;10.0.0.254:52420;2020-06-12;575;0;220;2956;0;;;;;;"azsdk-python-storage-blob/12.8.1 Python/3.12.2 (Linux-5.15.153.1-2.cm2-x86_64-with-glibc2.31)";;"4f061460-3f79-11ef-b188-a665be233668";;;;;;;;
2.0;2024-07-11T11:33:00.5570855Z;ListBlobs;Success;200;7;2;authenticated;storagecasbx01we;storagecasbx01we;blob;"https:///<endpoint>.blob.core.windows.net:443/cp-images?restype=container&amp;comp=list";"/storagecasbx01we/cp-images";67d5e450-701e-002a-2286-d3f759000000;0;10.0.0.254:52420;2020-06-12;575;0;220;2956;0;;;;;;"azsdk-python-storage-blob/12.8.1 Python/3.12.2 (Linux-5.15.153.1-2.cm2-x86_64-with-glibc2.31)";;"540c6748-3f79-11ef-b188-a665be233668";;;;;;;;
2.0;2024-07-11T11:32:45.3248984Z;GetBlob;AnonymousIpAuthorizationError;403;4;4;anonymous;;storagecasbx01we;blob;"https:///<endpoint>.blob.core.windows.net:443/cp-images/images.png";"/";1392860f-f01e-000b-4186-d3d322000000;0;163.116.166.103:8762;2009-09-19;624;0;105;246;0;;;;;;"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36";"https://<app_service>.azurewebsites.net/";;;;;;;;;
2.0;2024-07-

Python code part:

@app.route("/")
def view_photos():
    blob_items = container_client.list_blobs() # list all the blobs in the container

    img_html = "<div style='display: flex; justify-content: space-between; flex-wrap: wrap;'>"

    for blob in blob_items:
        blob_client = container_client.get_blob_client(blob=blob.name) # get blob client to interact with the blob and get blob url
        img_html += "<img src='{}' width='auto' height='200' style='margin: 0.5em 0;'/>".format(blob_client.url) # get the blob url and append it to the html
    
    img_html += "</div>"

    # return the html with the images
    return """
    <head>
    <!-- CSS only -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    </head>
    <body>
        <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
            <div class="container">
                <a class="navbar-brand" href="/">Photos App</a>
            </div>
        </nav>
        <div class="container">
            <div class="card" style="margin: 1em 0; padding: 1em 0 0 0; align-items: center;">
                <h3>Upload new File</h3>
                <div class="form-group">
                    <form method="post" action="/upload-photos" 
                        enctype="multipart/form-data">
                        <div style="display: flex;">
                            <input type="file" accept=".png, .jpeg, .jpg, .gif" name="photos" multiple class="form-control" style="margin-right: 1em;">
                            <input type="submit" class="btn btn-primary">
                        </div>
                    </form>
                </div> 
            </div>
        
    """ + img_html + "</div></body>"

And also vNet integration is properly working with Put and List requests (so, I have private outbound IP. But for Get request it shows public IP address. Can smbd help with that, because really stucked :(


Solution

  • When using your code blob_client.url, images were not loading. Instead of using blob_client.url I used SAS URL of each blob which worked for me.

    Below given code worked for me.

    I have generated SAS token and configured the URL

    from flask import Flask, render_template
    from datetime import timedelta,datetime
    from azure.storage.blob import BlobServiceClient, generate_blob_sas,BlobSasPermissions
    
    app = Flask(__name__)
    
    account_name="xxxxxxxxxxxxxxx"
    container_name="xxxxxxxxxxxxx"
    key ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    connection_string="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    
    blobservice_client= BlobServiceClient.from_connection_string(connection_string)
    container_client= blobservice_client.get_container_client(container_name)
    
    def gernrate_blob_sas_url(blob_name):
        sas = generate_blob_sas(
                account_name= account_name,
                account_key= key,
                container_name= container_name,
                blob_name= blob_name,
                permission=BlobSasPermissions(read=True),
                expiry= datetime.now() + timedelta(hours=1)
            )
        sas_url =f"https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}?{sas}"
        return sas_url
    
    @app.route('/')
    def index():
        blob_items = container_client.list_blobs() # list all the blobs in the container
    
        img_html = "<div style='display: flex; justify-content: space-between; flex-wrap: wrap;'>"
    
        for blob in blob_items:
            blob_sasurl=gernrate_blob_sas_url(blob.name)         # get blob client to interact with the blob and get blob url
            img_html += "<img src='{}' width='auto' height='200' style='margin: 0.5em 0;'/>".format(blob_sasurl) # get the blob sas url and append it to the html
        
        img_html += "</div>"
    
        # return the html with the images
        return """
        <head>
        <!-- CSS only -->
            <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
        </head>
        <body>
            <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
                <div class="container">
                    <a class="navbar-brand" href="/">Photos App</a>
                </div>
            </nav>
            <div class="container">
                <div class="card" style="margin: 1em 0; padding: 1em 0 0 0; align-items: center;">
                    <h3>Upload new File</h3>
                    <div class="form-group">
                        <form method="post" action="/upload-photos" 
                            enctype="multipart/form-data">
                            <div style="display: flex;">
                                <input type="file" accept=".png, .jpeg, .jpg, .gif" name="photos" multiple class="form-control" style="margin-right: 1em;">
                                <input type="submit" class="btn btn-primary">
                            </div>
                        </form>
                    </div> 
                </div>
            
        """ + img_html + "</div></body>"
    if __name__ =="__main__":
        app.run()
    

    OUTPUT:

    Before :

    After :