TylerJSimpson
TylerJSimpson

Reputation: 13

Azure Container App not authorized to access Storage Account Table

I am having a difficult time with the Networking between my Azure Container App (ACA) and Azure Storage Account Table.

Overview

I have a python (Flask) app API that is containerized with Docker. I am utilizing Azure Container Registry (ACR) and ACA with the CICD setup on commits to my main branch in GitHub. I recently wanted to implement authentication, so I created an Azure Storage Account Table to verify API keys. This works GREAT locally. It does not work at all from the cloud. I have narrowed it down to a networking error which I will elaborate on. Below I will provide what I'm doing locally as well as in the cloud in the hopes that you can help me troubleshoot.

Local (working)

Building the Docker Image

docker build -t testapp_${env}:${VERSION} --platform linux/amd64 .

Running the Docker image with the table connection string

docker run -p 8000:80 -e AZURE_TABLE_CONN_STRING='hardcodingfortesting' testapp_${env}:${VERSION}

POST successfully

curl -X POST http://localhost:8000/parse-report \
     -H "X-API-KEY: 123" \
     -H "Content-Type: application/json" \

The logic works great I can alter the API key and it will tell me it does not match.

Cloud (not working)

Now the exact same package is being pushed to ACR and ACA and I get an error when I try to post.

POST unsuccessful

curl -X POST https://removingforsecurity.io \
     -H "X-API-KEY: 123" \
     -H "Content-Type: application/json" \

I know with a great deal of certainty that this is a networking issue. This is because in the Networking tab of my Storage Account if I change Public Network Access to Enabled from all networks I can successfully POST.

Error log in ACA after attempting POST:

Content: {"odata.error":{"code":"AuthorizationFailure","message":{"lang":"en-US","value":"This request is not authorized to perform this operation.\nRequestId:9e37b393-b002-006b-1217-64ed0a000000\nTime:2024-02-20T16:08:39.0510443Z"}}}

I have tried the following to resolve this issue:

Please let me know what I should do.

EDIT: Adding Dockerfile

# Python runtime image base
FROM python:3.10-slim

# Set the working directory in the container
WORKDIR /app

# Ensure requirements are copied
COPY requirements.txt /app/

# Install requirements
RUN pip install --no-cache-dir -r requirements.txt

# Copy application
COPY . /app

# Where to find application instance
ENV FLASK_APP=main_parser.py

# Expose port
EXPOSE 80

# Run command
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:80", "main_parser:app"]

Upvotes: 1

Views: 1172

Answers (1)

Sampath
Sampath

Reputation: 3639

The authorization issue between your Azure Container App (ACA) and Azure Storage Account Table may be due to IP address restrictions or Managed Identity permissions read access roles.

  • Guide on using storage mounts in Azure Container Apps

  • I followed DOC to Deploy a Flask Web App as a Container in Azure Container Apps .

  • Connect to an Azure File Share via a Private Endpoint.

  • Set up a private endpoint with a private link for Azure Container Registry. If you are using a private link, make sure to run Azure storage and the Azure container on the same private endpoint.

  • The below Flask code with Azure Storage Table display, which is deployed to Azure Container Apps:

app .py:

import os
from flask import (Flask, redirect, render_template, request, send_from_directory, url_for)
from azure.data.tables import TableServiceClient
from azure.core.credentials import AzureNamedKeyCredential

app = Flask(__name__)

# Azure Storage Account details
account_name = "Azureaccount_name"
account_key = "Azureaccount_key"
table_name = "Azuretable_name"
table_service_endpoint = f"https://{account_name}.table.core.windows.net/"

# Create the AzureNamedKeyCredential
credential = AzureNamedKeyCredential(account_name, account_key)

# Create the TableServiceClient using the connection string
table_service_client = TableServiceClient(endpoint=table_service_endpoint, credential=credential)

# Get the table client for the specified table
table_client = table_service_client.get_table_client(table_name)

@app.route('/')
def index():
    print('Request for index page received')
    return render_template('index.html')

@app.route('/favicon.ico')
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static'),
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')

@app.route('/hello', methods=['POST'])
def hello():
    name = request.form.get('name')

    if name:
        print('Request for hello page received with name=%s' % name)
        try:
            entities = table_client.list_entities()
            entities_list = []
            for entity in entities:
                entities_list.append(entity)
            return render_template('hello.html', name=name, entities=entities_list)
        except Exception as e:
            error_message = f"An error occurred: {e}"
            print(error_message)
            return render_template('hello.html', name=name, error=error_message)
    else:
        print('Request for hello page received with no name or blank name -- redirecting')
        return redirect(url_for('index'))

if __name__ == '__main__':
    app.run()

hello.html:


<!doctype html>
<html>
<head>
    <title>Hello Azure - Python Quickstart</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css') }}">
    <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
<main>
    <div class="px-4 py-3 my-2 text-center">
        <img class="d-block mx-auto mb-4" src="{{ url_for('static', filename='images/azure-icon.svg') }}" alt="Azure Logo" width="192" height="192"/>
        <h1 class="display-6 fw-bold">Hello {{name}}</h1>
        <p class="fs-5">It is nice to meet you!</p>
        <a href="{{ url_for('index') }}" class="btn btn-primary btn-lg px-4 gap-3">Back home</a>
    </div>
    {% if entities %}
    <div class="container">
        <h2>Entities in the Azure Table:</h2>
        <ul>
            {% for entity in entities %}
            <li>
                <strong>PartitionKey:</strong> {{ entity.PartitionKey }} <br>
                <strong>RowKey:</strong> {{ entity.RowKey }} <br>
                {% for key, value in entity.items() if key not in ['PartitionKey', 'RowKey'] %}
                <strong>{{ key }}:</strong> {{ value }} <br>
                {% endfor %}
            </li>
            {% endfor %}
        </ul>
    </div>
    {% endif %}
    {% if error %}
    <div class="container">
        <p>An error occurred: {{ error }}</p>
    </div>
    {% endif %}
</main>
</body>
</html>




index.html:

<!doctype html>

<html>

<head>

<title>Hello Azure - Python Quickstart</title>

<link  rel="stylesheet"  href="{{ url_for('static',  filename='bootstrap/css/bootstrap.min.css') }}">

<link  rel="shortcut icon"  href="{{ url_for('static',  filename='favicon.ico') }}">

</head>

<body>

<main>

<div  class="px-4 py-3 my-2 text-center">

<img  class="d-block mx-auto mb-4"  src="{{ url_for('static',  filename='images/azure-icon.svg') }}"  alt="Azure Logo"  width="192"  height="192"/>

<h1  class="display-6 fw-bold text-primary">Welcome to Azure</h1>

</div>

<form  method="post"  action="{{url_for('hello')}}"  class="col-md-6 mx-auto text-center">

<label  for="name"  class="form-label fw-bold fs-5">Could you please tell me your name?</label>

<div  class="d-grid gap-2 d-sm-flex justify-content-sm-center align-items-center my-1">

<input  type="text"  class="form-control"  id="name"  name="name"  style="max-width: 256px;">

</div>

<div  class="d-grid gap-2 d-sm-flex justify-content-sm-center my-2">

<button  type="submit"  class="btn btn-primary btn-lg px-4 gap-3">Say Hello</button>

</div>

</form>

</main>

</body>

</html>




requirements.txt:


Flask==2.2.2

gunicorn

Werkzeug==2.2.2

azure-storage-blob

azure-data-tables

Dockerfile:

# syntax=docker/dockerfile:1

FROM python:3.11

WORKDIR /code

COPY requirements.txt .

RUN pip3 install -r requirements.txt

COPY . .

EXPOSE 50505

ENTRYPOINT ["gunicorn", "app:app"]

.dockerignore

.git*

**/*.pyc

.venv/

Local: enter image description here

build a Docker image from a Dockerfile. docker build --tag flask-demo1 .

enter image description here

  • Create a container registry and add a new tag to an existing image. docker tag 8xxxxxe63 sampath344.azurecr.io/samapth-app/flask-demo:v2

enter image description here

  • Log in to an Azure Container Registry (ACR) using the az acr login command, and push a Docker image to an Azure Container Registry (ACR).
az acr login --name "ContainerregistryName" --password "password" --username "password"

enter image description here

docker push sampath344.azurecr.io/samapth-app/flask-demo:v2 

enter image description here

  • Create a container app by selecting the container registry.

enter image description here

Azure: enter image description here

Upvotes: 0

Related Questions