Azure 容器应用程序无权访问存储帐户表

问题描述 投票:0回答:1

我的 Azure 容器应用程序 (ACA) 和 Azure 存储帐户表之间的网络连接遇到困难。

概述

我有一个使用 Docker 进行容器化的 python (Flask) 应用程序 API。我正在利用 Azure 容器注册表 (ACR) 和 ACA 以及 CICD 设置来提交到 GitHub 中的主分支。我最近想实现身份验证,因此我创建了一个Azure存储帐户表来验证API密钥。这在本地效果很好。它在云端根本不起作用。我已将其范围缩小到网络错误,我将对此进行详细说明。下面我将我在本地和云端所做的事情提供出来,希望你能帮助我解决问题。

本地(工作)

构建 Docker 镜像

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

使用表连接字符串运行 Docker 映像

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

发布成功

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

这个逻辑非常有效,我可以更改 API 密钥,它会告诉我它不匹配。

云(不工作)

现在完全相同的包被推送到 ACR 和 ACA,当我尝试发布时出现错误。

发布不成功

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

我非常确定这是一个网络问题。这是因为在我的存储帐户的网络选项卡中,如果我将 公共网络访问 更改为 从所有网络启用,我可以成功 POST。

尝试 POST 后登录 ACA 时出错:

Content: {"odata.error":{"code":"AuthorizationFailure","message":{"lang":"en-US","value":"该请求无权执行此操作。 请求 ID:9e37b393-b002-006b-1217-64ed0a000000 时间:2024-02-20T16:08:39.0510443Z"}}}

我已尝试以下方法来解决此问题:

  • IAM 将 ACA 的托管身份设置为 Storage Table Data Contributor。我在特定存储帐户的订阅级别和资源级别尝试了此操作。我等了几个小时以确保这不是时间问题。
  • 从 ACA 获取出站 IP 地址并将其添加到存储帐户防火墙。
  • 存储帐户网络尝试从 Microsoft 网络路由更改为 Internet 路由。

请让我知道我应该做什么。

编辑:添加 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"]
flask azure-table-storage azure-container-registry azure-container-apps
1个回答
0
投票

Azure 容器应用程序 (ACA) 和 Azure 存储帐户表之间的授权问题可能是由于 IP 地址限制或托管标识权限读取访问角色造成的。

  • 在 Azure 容器中使用存储挂载的指南 Apps

  • 在 Azure 容器应用程序 (ACA) 中使用存储的指南,涵盖各种 存储

  • 我按照 DOC 将 Flask Web 应用程序部署为 Azure 容器应用程序中的容器。

  • 通过专用端点连接到 Azure 文件共享。

  • 使用 Azure 容器 Registry 的专用链接设置专用端点。如果您使用专用链接,请确保在同一专用终结点上运行 Azure 存储和 Azure 容器。

  • 以下带有 Azure 存储表显示的 Flask 代码,已部署到 Azure 容器应用程序:

应用程序.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>




需求.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/

本地: enter image description here

从 Dockerfile 构建 Docker 映像。

docker build --tag flask-demo1 .

enter image description here

  • 创建容器注册表并向现有映像添加新标签。
    docker tag 8xxxxxe63 sampath344.azurecr.io/samapth-app/flask-demo:v2

enter image description here

  • 使用
    az acr login
    命令登录 Azure 容器注册表 (ACR),并将 Docker 映像推送到 Azure 容器注册表 (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

  • 通过选择容器注册表创建容器应用程序。

enter image description here

蔚蓝: enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.