Technical Blog テクニカルブログ
  1. HOME
  2. テクニカルブログ
  3. Cloud Runでプレビューになったマルチコンテナ構成によるAPIの認証認可の実装方法

Cloud Runでプレビューになったマルチコンテナ構成によるAPIの認証認可の実装方法

投稿者:今井

はじめに

こんにちは。CI部の今井です。

このテックブログでは、Google Cloudで最近プレビューになったCloud Runのマルチコンテナ構成を使用してAPIの認証認可をサイドカー側に実装する方法を説明します。

この記事の方法を利用することでメインの処理を実行するコンテナと認証認可を実行するコンテナを分離することができるため、コードの更新が容易に実施することが可能となります。

APIのセキュリティと認証認可の重要性

現代のアプリケーションでは、APIを使用してデータやサービスにアクセスすることが一般的です。しかし、APIのセキュリティは非常に重要であり、適切な認証認可メカニズムを実装する必要があります。APIへの不正なアクセスや権限のないリソースへのアクセスは、機密性やデータの完全性に関する深刻なリスクを引き起こす可能性があります。

認証は、ユーザーまたはアプリケーションが自分自身を正当なエンティティとして証明するプロセスです。一方、認可は、認証されたユーザーがどのリソースや操作にアクセスできるかを決定するプロセスです。適切な認証認可メカニズムの実装により、アプリケーションは正当なユーザーのみにアクセスを許可し、必要な権限でのみ操作を許可することができます。

Open Policy Agent(OPA)の概要と利点

Open Policy Agent(OPA)は、クラウドネイティブなアプリケーションの認証認可ポリシー管理に役立つオープンソースのプロジェクトです。OPAは柔軟なポリシーエンジンを提供し、APIの認証認可ルールを明確に定義し、維持するための効果的な手段を提供します。

OPAはポリシーファイルとして表現されるルールベースのシステムであり、独自の言語(Rego)を使用してポリシーを記述します。Rego言語は直感的で柔軟な構文を持ち、複雑な認証認可ルールを表現するための豊富な機能を提供します。

OPAの利点の一つは、ポリシーの独立性と拡張性です。アプリケーションコードから分離されたポリシーロジックを管理することで、アプリケーションの柔軟性と保守性が向上します。さらに、OPAはクラウドネイティブな環境での使用に最適化されており、コンテナやマイクロサービスとの統合が容易です。

OPAを使用することで、APIの認証認可ルールを中央で一元管理し、実行時に柔軟に評価できます。これにより、セキュリティの向上とアプリケーションの信頼性の確保が可能となります。

次の章では、Cloud Runのマルチコンテナ構成を使用してOPAをサイドカーとしてデプロイする方法について詳しく説明します。

アプリケーションについて

今回、デプロイするCloud Runの構成について、先に説明します。Cloud Runでのマルチコンテナ構成ではHTTPS通信を受信するコンテナは1つ、そしてサイドカーコンテナが1つ以上存在する構成のみが可能になっています。サイドカーのコンテナはHTTPS通信を受信したコンテナと相互に通信することはできますが、サイドカーコンテナ自身はHTTPS通信を受信することはできません。

今回の構成では、以下の画像の通りサイドカーコンテナはlocalhost:5050を使用してHTTPS通信を受信するコンテナと相互に通信する想定となります。

今回のブログで利用するCloud Runのコードはこちらのリポジトリにすべてございますので、ご自由に利用してください。

メインの処理を実行するコンテナはHTTPS通信を受信し、そのリクエストのデータの内容をサイドカーコンテナのOPAに確認を取り、認証認可が通ればHello Worldを返し、通らなければ何も返さないという単純な処理としました。

import json
import requests
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/test', methods=['POST'])
def hello():
    allowed = check_authorization(request)
    if allowed == True:
        return jsonify({"text": "hello world, alice!"})
    else:
        return jsonify({})

def get_requestdata(request):
    return json.loads(request.get_data())

def check_authorization(request):
    user = get_requestdata(request)
    input_data = json.dumps({"input": {"user": user['user']}})
    headers = {'content-type': 'application/json'}

    url = "http://localhost:5050/v1/data/example"  # OPAのURL(適宜変更)
    response = requests.post(url, data=input_data, headers=headers)

    response_json = response.json()
    allowed = response_json["result"]["allow"]
    print("-----")
    print(user)
    print("allowed:" + str(allowed))
    print("-----")
    return allowed

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

requirements.txtやdockerfileの内容はリポジトリ内のhelloworldフォルダを確認するようにしてください。

次に、OPAのポリシーファイルを作成します。今回は単純なものでHTTPS通信を送信してきたユーザーがaliceであれば認可し、aliceでなければ認可しないポリシーとしました。

package example

import future.keywords.if

# デフォルトの拒否ルールを定義します
default allow := false

# alice は許可します
allow if input.user == "alice"

dockerfileでは上記のポリシーをコンテナに含むように設定します。

# ベースイメージとして公式の OPA コンテナを使用します
FROM openpolicyagent/opa:latest

# ポリシーファイルをコンテナ内にコピーします
COPY example.rego /app/example.rego

# Cloud Run のサイドカーに必要なポートを公開します
EXPOSE 5050

# デフォルトのコマンドを指定します(OPAのサーバーを起動します)
CMD ["run", "--server", "--addr=:5050", "/app/example.rego", "--log-level", "debug"]

Cloud Runのデプロイ

Cloud Runをデプロイするためにはコンテナを準備しなければいけません。今回はコンテナをビルドするためにCloud Buildサービスを利用し、コンテナのホストにはArtifact Registryを利用します。

前準備として、Cloud BuildがCloud Runをデプロイできるように有効化しておくこととArtifact Registryにmy-containerリポジトリを作成してください。

準備が完了したため、Cloud Buildからコンテナのビルド、プッシュ、Cloud Runのデプロイを実施します。Cloud Build用のYAMLは以下のように作成しました。こちらのブログを参考にさせていただいています。

steps:
  - name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "${_IMAGE_HELLOWORLD}", "./helloworld"]
    id: BUILD_HELLOWORLD_CONTAINER
    waitFor: ["-"]

  - name: "gcr.io/cloud-builders/docker"
    args: ["build", "-t", "${_IMAGE_OPASIDECAR}", "./opasidecar"]
    id: BUILD_OPASIDECAR_CONTAINER
    waitFor: ["-"]

  - name: "gcr.io/cloud-builders/docker"
    args: ["push", "${_IMAGE_HELLOWORLD}"]
    id: PUSH_HELLOWORLD_CONTAINER
    waitFor:
      - BUILD_HELLOWORLD_CONTAINER

  - name: "gcr.io/cloud-builders/docker"
    args: ["push", "${_IMAGE_OPASIDECAR}"]
    id: PUSH_OPASIDECAR_CONTAINER
    waitFor:
      - BUILD_OPASIDECAR_CONTAINER

  - name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
    entrypoint: gcloud
    args:
      [
        "run",
        "services",
        "replace",
        "service.yaml",
        "--region",
        "asia-northeast1",
      ]
    id: DEPLOY_MULTICONTAINER
    waitFor:
      - PUSH_HELLOWORLD_CONTAINER
      - PUSH_OPASIDECAR_CONTAINER

substitutions:
  _REGISTRY: <Artifact Registryのパスに変更>/my-container
  _IMAGE_HELLOWORLD: ${_REGISTRY}/helloworld:latest
  _IMAGE_OPASIDECAR: ${_REGISTRY}/opasidecar:latest

images:
  - ${_IMAGE_HELLOWORLD}
  - ${_IMAGE_OPASIDECAR}

options:
  dynamic_substitutions: true

マルチコンテナ構成のCloud Runは以下のYAMLによりデプロイする形にしています。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  annotations:
     run.googleapis.com/launch-stage: BETA
  name: opa-sidecar-challenge
spec:
  template:
    metadata:
      annotations:
        run.googleapis.com/execution-environment: gen1 #or gen2
    spec:
      containers:
      - image: <Artifact Registryのパスに変更>/my-container/helloworld:latest
        ports:
          - containerPort: 8080
      - image: <Artifact Registryのパスに変更>/my-container/opasidecar:latest

YAML内の<Artifact Registryのパスに変更>となっているところは、Artifact Registryのmy-containerのパスに置換する必要があります。以下の画像の通りでmy-containerの中のコピーできるところからコピーして、ご自身の環境のものに変更してください。

上記の変更を行った後に、以下のコマンドを実行するとCloud Runのデプロイが行われます。

gcloud builds submit . --config=cloudbuild.yaml

デプロイされるとCloud Runにopa-sidecar-challengeが存在しているはずです。

そして、今回は呼び出しの際の認証が不要なパターンで行うため、呼び出しを未認証でも許可とします。

APIが認証認可されるか確認する

ここまでで、Cloud Runのデプロイは完了しました。次はデプロイしたCloud Runを実際にAPIとして呼び出してみて、ちゃんとOPAの認証認可機能が動いているかを確認します。

Cloud Runをデプロイすると呼び出し用のURLが発行されます。発行されたURLをコピーしてください。

コピーしたURLを以下の<コピーしたURL>の部分と置換してください。

curl -X POST <コピーしたURL>/test -d '{"user":"alice"}'

このコマンドを実行するとuserはaliceのため、OPAの認証認可が通るはずなので{"text":"hello world, alice!"}が返却されてくるはずです。

では、userがaliceではない場合はどうなるのか、ということでuserをbobに変更してコマンドを実行してみます。

curl -X POST <コピーしたURL>/test -d '{"user":"bob"}'

ダメでした。ちゃんとOPAの認証認可機能によりはじかれているようです。

Cloud Runのログの確認

Cloud Runのログ上でもOPAの認証認可のログを確認することができます。以下の画像のように1回目はaliceなのでtrueとなり、2回目はbobなのでfalseになっています。

おわりに

本ブログでは、Cloud Runのマルチコンテナ構成を使用してOpen Policy Agent(OPA)をサイドカーとしてデプロイし、APIの認証認可を実装する方法について説明しました。今回は検証目的もありOPAのポリシーをとても単純なものとしていますが、実際はもっと複雑なポリシーを実装する必要があります。

今回のCloud Runのマルチコンテナ構成を活用することで、アプリケーションにOPAサイドカーコンテナを追加することができます。OPAはポリシーベースのアクセス制御を提供し、APIの認証認可ルールを柔軟に管理するための強力なツールです。OPAのポリシーファイルを作成し、APIエンドポイントとの統合を行うことで、細かなアクセス制御を実現することができます。

Cloud RunとOPAの組み合わせは、クラウドネイティブな環境におけるAPIセキュリティの基盤となります。新たな認証認可要件やポリシールールの変更に柔軟に対応するため、OPAのルールの追加や変更、ポリシーファイルの再デプロイが可能です。また、ログや監査のための統合も検討できます。

結論として、Cloud RunとOPAの組み合わせは、APIのセキュリティと認証認可を強化するための優れた手段です。柔軟なポリシールールの管理と統合により、アプリケーションの信頼性とセキュリティを向上させることができます。今まではCloud Runではマルチコンテナ構成が取れなかったので、OPAをサイドカーとして走らせることはできませんでしたが、プレビューですがマルチコンテナ構成をとることができるようになったため、これからはCloud Runでも増えていくのかなと予想しています。

ここまでお読みいただきありがとうございました。

参考文献

ページのトップへ