Functions: APIゲートウェイを使用したAPIキーの検証

このチュートリアルでは、Oracle Functionsを使用して、Oracle API Gatewayから渡されるAPIキーを検証します。APIキーは、クライアントに特定のトークンを渡すように要求することでAPIを保護するための単純な方法です。ゲートウェイは、トークンをカスタム認可プロバイダとして使用して、リクエストを検証できます。トークンを検証し、認証されたJSONレスポンスを返すPythonファンクションを作成します。

主なタスクは:

  • 必要な情報を収集します。
  • ファンクションのアプリケーションを作成します。
  • 「Hello World!」ファンクションを作成します。
  • APIキーを検証するようにファンクションを変換します。
  • ファンクションをデプロイおよびテストします。
  • ファンクションのAPIゲートウェイを作成します
  • APIゲートウェイを使用して、インターネットからファンクションをコールします。
この図は、Oracleファンクションの実行に使用されるOCIコンポーネントを示しています。

その他の情報については、次のWebサイトを参照してください。

開始する前に

このチュートリアルを正常に実行するには、次が必要です:

OCIアカウントの要件
ソフトウェアの要件

Oracle CLI

Oracle Cloud Shell

  • クラウド・シェルを使用する場合、前述のソフトウェアのリストはすでにインストールされています。

1. 必要な情報の収集

チュートリアルを完了するために必要なすべての情報を収集します。次の情報をメモ帳にコピーします。

コンパートメント情報の取得

コンパートメントを作成するには、コンパートメントの作成を参照してください。コンパートメントを作成したら、コンパートメントOCIDとコンパートメント名を保存します。

既存のコンパートメントからコンパートメントOCIDを取得するには:

  1. ナビゲーション・メニューを開き、「アイデンティティとセキュリティ」をクリックします。「アイデンティティ」で、「コンパートメント」をクリックします。
  2. コンパートメントを選択します。
  3. OCIDフィールドの「コピー」リンクをクリックします。

コンパートメントOCIDとコンパートメント名を保存します。

収集された情報

チュートリアル用に次の情報を書き留めていることを確認してください。

  • コンパートメント名: <your-compartment-name>

    例: my-compartment

  • コンパートメントID: <your-compartment-OCID>

    例: ocid1.compartment.oc1.aaaaaaa...

  • VCN名: <your-vcn-name>

    例: my-vcn

    ナビゲーション・メニューを開いて「ネットワーキング」をクリックし、「仮想クラウド・ネットワーク」をクリックします。

  • VCNパブリック・サブネット名: <Public-Subnet-your-vcn-name>

    例: Public-Subnet-my-vcn

    ナビゲーション・メニューを開いて「ネットワーキング」をクリックし、「仮想クラウド・ネットワーク」をクリックします。作成したVCNをクリックします。

2. 必要な構成の実行

チュートリアルに必要な構成をすべて実行します。

Functionsアプリケーションの作成

アプリケーションを作成するには、次のステップに従います。

  1. ナビゲーション・メニューを開き、「開発者サービス」をクリックします。「ファンクション」で、「アプリケーション」をクリックします。
  2. 「コンパートメント」ドロップダウンからコンパートメントを選択します。
  3. 「アプリケーションの作成」をクリックします。
  4. フォーム・データを入力します。
    • 名前: <your-app-name>
    • VCN: <your-vcn-name>
    • サブネット: <Public-Subnet-your-vcn-name>
  5. 「作成」をクリックします。

アプリケーションが作成されます。

HTTPSのイングレス・ルールの設定
  1. ナビゲーション・メニューを開いて「ネットワーキング」をクリックし、「仮想クラウド・ネットワーク」をクリックします。
  2. Oracle Functionsアプリケーションに使用したVCNの名前をクリックします。
  3. 新しいVCNが表示された状態で、「パブリック」サブネット・リンクをクリックします。

    パブリック・サブネット情報は、ページの下部にあるセキュリティ・リストとともに表示されます。

  4. 「デフォルト・セキュリティ・リスト」リンクまたは適切なセキュリティ・リスト・リンクをクリックします。

    VCNのデフォルトのイングレス・ルールが表示されます。

  5. 「イングレス・ルールの追加」をクリックします。

    「イングレス・ルールの追加」ダイアログが表示されます。

  6. イングレス・ルールに次の情報を入力します。すべてのデータを入力したら、「イングレス・ルールの追加」をクリックします

    イングレス・ルールを次のように入力します:

    • ステートレス:選択
    • ソース・タイプ: CIDR
    • ソースCIDR: 0.0.0.0/0
    • IPプロトコル: TCP
    • ソース・ポート範囲: (空白のまま)
    • 宛先ポート範囲: 443
    • 説明: アプリケーションのVCN

    「イングレス・ルールの追加」をクリックすると、パブリック・サブネットへのHTTPS接続が許可されます。

FunctionsへのAPIゲートウェイ・アクセスのポリシーの設定

次に、APIゲートウェイによるファンクションの呼出しを許可するポリシーを設定します。

最初に、APIゲートウェイの動的グループを作成します。

  1. ナビゲーション・メニューを開き、「アイデンティティとセキュリティ」をクリックします。「アイデンティティ」で、「動的グループ」をクリックします。
  2. 「動的グループの作成」をクリックします。
  3. 次の情報を入力して、動的グループを定義します。
    • 名前: <name-for-your-dynamic-group>
    • 「一致ルール」で、ルール1: <the-rule-text>を使用します

    次に、サンプル名と、入力する必要があるルールを示します。

    • 名前: api-gtw-func-dynamic-group
    • 「一致ルール」で、ルール1: ALL {resource.type = 'ApiGateway', resource.compartment.id = 'ocid1.compartment.<your-compartment-OCID>'}を使用します
  4. 作成」をクリックします。

ここで、APIゲートウェイのポリシーを作成します。

  1. ナビゲーション・メニューを開き、「アイデンティティとセキュリティ」をクリックします。「アイデンティティ」で、「ポリシー」をクリックします。
  2. ポリシーの作成をクリックします。
  3. ポリシーを定義するには、次の情報を入力します。
    • 名前: <name-for-your-policy>
    • 説明: <description-for policy>
    • コンパートメント: <name-of-functions-compartment>

    「ポリシー・ビルダー」セクションで:

    • 「手動エディタの表示」をクリックします。
    • テキスト・ボックスにポリシーを入力します。次に例を示します:
      Allow dynamic-group  api-gtw-func-dynamic-group to use functions-family in compartment <your-compartment-name>
      ノート

      最後のパラメータは、コンパートメントOCIDではなく、コンパートメントです。
  4. 「作成」をクリックします。

APIゲートウェイによるFunctionsの使用を許可するポリシーが作成されました。

「Hello World」Pythonファンクションの作成
  1. ターミナルを開きます。
  2. ファンクションを格納するディレクトリを作成し、そのディレクトリに移動します。
    mkdir my-dir-name
    cd my-dir-name                        
                         
  3. Fnを使用してPythonの「Hello World」ファンクションを作成します。
    fn init --runtime python my-func-name

    このコマンドは、ファンクションおよび構成ファイルを含むmy-func-nameという名前のディレクトリを作成します。

  4. そのディレクトリに移動します。
  5. ファンクションをデプロイします。
    fn -v deploy --app your-app-name

    Dockerイメージが作成され、OCIRにプッシュされ、最終的にOracle Functionsにデプロイされると、様々なメッセージが表示されます。

  6. ファンクションを呼び出します。
    fn invoke your-app-name my-func-name

    戻り値: {"message": "Hello World"}

  7. パラメータを指定してファンクションを呼び出します。
    echo -n '{"name":"Bob"}' | fn invoke your-app-name my-func-name

    戻り値: {"message": "Hello Bob"}

3. APIゲートウェイの作成

ファンクションをコールするには、APIゲートウェイを作成します。

APIゲートウェイの作成

APIゲートウェイを作成するには:

  1. ナビゲーション・メニューを開き、「開発者サービス」をクリックします。「API管理」で、「ゲートウェイ」をクリックします。
  2. 「コンパートメント」ドロップダウンからコンパートメントを選択します。
  3. 「ゲートウェイの作成」をクリックします
  4. 次の情報を入力して、APIゲートウェイを定義します。
    • 名前: <your-gateway-name>
    • タイプ: <Public>
    • コンパートメント: <your-compartment-name>
    • <your-vcn-name>の仮想クラウド・ネットワーク: <select-your-vcn>
    • <your-compartment-nameのサブネット: <your-public-subnet-name>
  5. 「作成」をクリックします。APIゲートウェイが作成されるまで数分間待ちます。
ゲートウェイのAPIデプロイメントの作成

次に、APIゲートウェイのデプロイメントを作成します。

  1. 画面左側の「リソース」セクションで、「デプロイメント」をクリックします。
  2. 「デプロイメントの作成」をクリックします。
  3. デプロイメント・タイプに「最初から」が選択されていることを確認します。
  4. デプロイメントを定義するには、「基本情報」セクションに入力します。
    • 名前: <your-deployment-name>
    • パス接頭辞(例): /tokens
    • コンパートメント: <your-compartment-name>
    • APIリクエスト・ポリシー: デフォルト値を使用します
    • APIロギング・ポリシー: 「情報」のデフォルト値を使用します
  5. 次へ」をクリックします。「ルート1」が選択された状態で「ルート」ダイアログが表示されます。
  6. ルートを定義するには、「ルート1」セクションに入力します。
    • パス: <your-route-path>

      例: /val-token

    • メソッド: GET POST
    • タイプ: Oracle Functions
    • <your-compartment-name>のアプリケーション: 作成したFunctionsアプリケーションを選択します。
    • ファンクション名: 構成セクションで作成したファンクションを選択します。
  7. 次へ」をクリックします。選択内容をまとめた「確認」ダイアログが表示されます。
  8. 「作成」をクリックします。デプロイメントが作成されます。
  9. ゲートウェイの「デプロイメント」リンクをクリックします。作成したデプロイメントのベース・エンドポイントをコピーします。

    例: https://aaaaa.apigateway.us-ashburn-X.oci.customer-oic.com/tokens

APIゲートウェイのテスト

APIゲートウェイおよびデプロイメントを作成すると、インストールをテストできます。curlコマンドの単純なスクリプトを作成します。curlのURLを作成するには、エンドポイントにデプロイメント・パスを追加します。

  1. スクリプト・ファイルtouch gtw01.sh && chmod 755 gtw01.shを作成します
  2. スクリプト・ファイルにcurlコマンドを追加します:
    #!/bin/bash
    curl <your-api-gateway-endpoint>/val-token
  3. コマンドの戻り値: {"message":"Hello World"}

APIゲートウェイがボイラー・プレートPythonファンクションに接続されました。次に、HTTPリクエストで渡された情報を表示するようにPythonファンクションを更新します。

4. APIキーを検証するためのファンクションの更新

次に、APIキーを検証するようにボイラー・プレートPythonファンクションを変更します。

開始Pythonコードの確認

ボイラー・プレート・ファンクションを見ると、Pythonファンクションは次のようになります。

import io
import json
import logging

from fdk import response


def handler(ctx, data: io.BytesIO = None):
    name = "World"
    try:
        body = json.loads(data.getvalue())
        name = body.get("name")
    except (Exception, ValueError) as ex:
        logging.getLogger().info('error parsing json payload: ' + str(ex))
    
    logging.getLogger().info("Inside Python Hello World function")
    return response.Response(
       ctx, response_data=json.dumps(
           {"message": "Hello {0}".format(name)}),
       headers={"Content-Type": "application/json"}
    )

このコードを開始点として使用して、後続の項では、ファンクションを、APIキーを検証してトークンを返すPythonファンクションに変換します。

Functions構成変数の作成

Oracle Functionsでは、リクエストで使用可能なコンテキストに構成データを格納できます。構成データは、アプリケーションまたはファンクションに格納できます。次のコマンドは、アプリケーション構成にAPIキーを格納します。

  • fn config app <your-app-name> FN_API_KEY ABCD

「ABCD」文字列は、サンプルのキー値です。

ファンクション構成値の設定の詳細は、Fn Projectのランタイム・コンテキストに関するチュートリアルを参照してください。

必要なパッケージおよびハンドラ・ファンクションの更新

まず、必要なパッケージのfunc.pyを更新します。

  1. 必要なパッケージの検証のために、func.pyimport文を更新します:
    import io
    import json
    import logging
    import datetime
    
    from datetime import timedelta
    from fdk import response
                    

    datetimeパッケージを使用して、返されるトークンの有効期限を設定します。

  2. 次に、ファンクションの本体を削除します。進捗状況に応じて、responseメソッドおよび関連するコードが追加されます。
    import io
    import json
    import logging
    import datetime
    
    from datetime import timedelta
    from fdk import response
                            
    
    def handler(ctx, data: io.BytesIO = None):                
    

これで、検証コードを使用してファンクションを更新する準備ができました。

ファンクションへの検証コードの追加

次に、APIキーを検証してレスポンスでトークンを返すコードを追加します。コメント付きのコードを次に示します。

import io
import json
import logging
import datetime

from datetime import timedelta
from fdk import response

def handler(ctx, data: io.BytesIO = None):
    auth_token = "invalid"
    token = "invalid"
    apiKey = "invalid"
    expiresAt = (datetime.datetime.utcnow() + timedelta(seconds=60)).replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat()
    
    try:
        auth_token = json.loads(data.getvalue())
        token = auth_token.get("token")
        
        app_context = dict(ctx.Config())
        apiKey = app_context['FN_API_KEY']
        
        if token == apiKey:
            return response.Response(
                ctx, 
                status_code=200, 
                response_data=json.dumps({"active": True, "principal": "foo", "scope": "bar", "clientId": "1234", "expiresAt": expiresAt, "context": {"username": "wally"}})
            )
    
    except (Exception, ValueError) as ex:
        logging.getLogger().info('error parsing json payload: ' + str(ex))
        pass
    
    return response.Response(
        ctx, 
        status_code=401, 
        response_data=json.dumps({"active": False, "wwwAuthenticate": "API-key"})
    )
  • handlerファンクションは、ctxおよびdataパラメータを介して、現在のリクエストに関するシステム情報を受け取ります。
  • このファンクションは、アプリケーション構成でFN_API_KEYが設定されていることを前提としています。次に、このファンクションは、構成値をcurl POSTリクエスト(-d '{"token":"ABCD"}')から送信されたトークン値と比較します。
  • 値が一致する場合、検証JSONメッセージが返されます。一致しない場合、401コードがJSONエラー・データとともに返されます。

ファンクション・コードが完成しました。これで、ファンクションをテストする準備が整いました。

ファンクションのテスト
  1. 更新されたファンクションを再デプロイします。
  2. ファンクションを呼び出して、ファンクションが機能していることを確認します。
  3. POSTデータをスクリプトに渡すようにgtw01.shスクリプトを更新します。
    /bin/bash
    curl -X POST -d '{"token":"ABCD"}' https://aaaaa.apigateway.us-ashburn-X.oci.customer-oic.com/tokens/val-token
  4. スクリプトgtw01.sh | jqを実行します
  5. APIキーが一致する場合、スクリプトからの出力は次のようになります:
    {
        "active": true,
        "principal": "foo",
        "scope": "bar",
        "clientId": "1234",
        "expiresAt": "2020-12-16T22:48:50+00:00",
        "context": {
        "username": "wally"
        }
    }

    APIキーが一致しない場合、エラー・メッセージが返されます。

    {
        "active": false,
        "wwwAuthenticate": "API-key"
    }                        
                        

    Oracleファンクションのサンプル・サイトからファンクションの完全なソース・コードをダウンロードできます。

完了しました。ボイラー・プレートPythonファンクションが、APIキーを検証する新しいファンクションに変換されました。このファンクションは、データをAPIゲートウェイに渡し、ファンクションで処理する方法を示します。