ノート:
- このチュートリアルでは、Oracle Cloudへのアクセスが必要です。無料アカウントにサインアップするには、Oracle Cloud Infrastructure Free Tierの開始を参照してください。
- Oracle Cloud Infrastructureの資格証明、テナンシおよびコンパートメントの値の例を使用します。演習を完了するときに、これらの値をクラウド環境に固有の値に置き換えます。
Microsoft Entra IDからのアクセス・トークンを使用したOracle Integrationへの安全なアクセス
イントロダクション
Oracle Integrationのお客様は、マルチクラウド戦略を採用しているため、多くの場合、異なるクラウド・プロバイダー間でビジネス・アプリケーションとプロセスを接続する必要があります。たとえば、Oracle Cloud Infrastructureアプリケーションからデータにアクセスする必要があるアプリケーションをMicrosoft Azureで実行しているとします。通常、Oracle Cloud Infrastructure Identity and Access Management (OCI IAM)からトークンを取得して、このデータを取得します。ただし、複数のクラウド・プロバイダを使用すると、複数のトークンを処理できるため、複雑になり、セキュリティ・リスクが生じる可能性があります。
1つのOAuthトークンを使用して、異なるクラウド・プロバイダ間でアプリケーションと統合できる場合の利便性について考えてみます。このチュートリアルでは、サード・パーティのOAuthプロバイダを使用してOracle Integrationフローを起動します。
アーキテクチャ
ソリューション・フローを視覚化します。
プロセスは、ユーザーまたはビジネス・アプリケーションがMicrosoft Entra IDからOAuthトークンを取得することから始まります。取得後、このトークンはOCI API Gatewayを介して公開されるエンドポイントの起動に使用されます。カスタム認可プロバイダOCIファンクション(以前のOracle Functions)を使用するように構成されたOCI APIゲートウェイは、最初にこの認可プロバイダ・ファンクションをコールしてトークンを検証します。検証に成功すると、実際のバックエンド・エンドポイント(Oracle Integrationフロー)が起動されます。
次に、このプロセスの実行の詳細を説明します。わかりやすくするために、次の3つのステップに分割します。
- Oracle Integration/Oracle Identity Cloud Service (IDCS)構成。
- OCI Functionsカスタム認可プロバイダの実装。
- OCI APIゲートウェイ構成。
Microsoft Entra IDおよびOCI IAMからアクセス・トークンを取得するために、リソース所有者パスワード資格証明(ROPC)およびJSON Webトークン(JWT)アサーション付与タイプをそれぞれ使用するのはなぜですか。
ROPCおよびJWTアサーション権限を一緒に使用すると、マルチクラウド環境で認証およびトークン交換を処理するための合理化されたセキュアなアプローチが提供されます。
-
ROPC権限付与:リソース所有者の資格証明を直接使用して、Microsoft Entra IDから初期アクセス・トークンを取得します。アクセス・トークンには、認証されたユーザーの一意の識別子を表す
upn
を含む様々なクレームが含まれます。このupn
クレームおよびtrusted private key
では、ユーザー・アサーションが生成されます。 -
JWTアサーション付与:ユーザー・アサーションは、OCIアイデンティティ・ドメインからアクセス・トークンを取得するための認可付与として直接使用されます。このアクセス・トークンはOCIによって認識され、Oracle Integrationフローのシームレスな起動が可能になります。
対象読者
- OCI IAMプロフェッショナルおよびOracle Integration管理者。
目的
-
Microsoft Entra IDのOAuth 2.0トークンを使用して、Oracle Integrationフローを起動します。
Microsoft Entra IDからアクセス・トークンを生成するには、OAuth 2.0 ROPC権限を使用します。OCIサービス(特にOCI API GatewayとOCI Functions)を使用します。OCI API Gatewayは、Oracle Integrationエンドポイントのフロントエンドとして機能します。認可プロバイダ・ファンクションを使用したAPIの認証レイヤーの追加がサポートされています。つまり、Microsoft Entra IDからOAuth 2.0トークンを検証し、JWTアサーション付与タイプを使用してOCI IAMのトークンと交換するロジックを作成して、Oracle Integrationフローを起動できます。
前提条件
-
OCIアカウント:アプリケーションを管理するためのOCIテナンシへの管理アクセス。
-
Microsoft Entra IDアカウント:アプリケーションを登録するためのMicrosoft Entra IDテナンシへの管理アクセス。
-
OCI APIゲートウェイ、OCI Functions、OCI IAM、PythonなどのOCIサービスに精通しています。
-
既存のOracle Integration。
-
Python 3.xがインストールされています。
-
必須OCI IAMポリシー:
-
OCIファンクションを作成するためのポリシー。
Allow group <group name> to use cloud-shell in compartment <function compartment> Allow group <group name> to manage repos in compartment <function compartment> Allow group <group name> to manage functions-family in compartment <function compartment> Allow group <group name> to use virtual-network-family in compartment <network compartment> Allow dynamic-group <dynamic group name> to use secret-family in compartment <vault compartment>
ノート:動的グループはタスク2で作成され、OCI IAM権限は、このチュートリアルで強調表示されているように、理想よりも広い範囲です。最低限の特権の原則を遵守し、より限定的な政策を実施しなければならない。
-
OCI APIゲートウェイ・デプロイメントを作成するためのポリシー。
Allow group <group name> to manage api-gateway-family in compartment <api gateway compartment> ALLOW any-user to use functions-family in compartment <function compartment> where ALL {request.principal.type= 'ApiGateway', request.resource.compartment.id = '<ocid of api gateway compartment id>'}
3. Policy for storing secrets in [OCI Vault](https://docs.oracle.com/en-us/iaas/Content/Identity/Concepts/commonpolicies.htm#sec-admins-manage-vaults-keys).
Allow group <group name> to use secret-family in compartment <vault compartment> Allow group <group name> to manage secret-family in compartment <vault compartment> Allow group <group name> to manage keys in compartment <vault compartment> Allow group <group name> to manage vaults in compartment <vault compartment>
ノート: プレースホルダ
<group name>
、<dynamic group name>
、<api gateway compartment>
、<function compartment>
、<vault compartment>
および<ocid of api gateway compartment id>
は、それぞれ、実際のグループ名、OCI動的グループ名、OCI API Gateway、OCI FunctionsおよびOCI Vaultがデプロイされているコンパートメント、およびOCI API GatewayコンパートメントのOracle Cloud Identifier (OCID)値に置き換える必要があります。 -
タスク1: Microsoft Entra IDを使用したアプリケーションの登録
保護されたリソース(グラフAPI)へのアクセスなど、Microsoft Entra IDのIAM機能を使用するには、アプリケーションを登録する必要があります。
-
アプリケーションの登録詳細は、「Microsoft IDプラットフォームへのアプリケーションの登録」を参照してください。
-
「概要」セクションの
Application (client) ID
値を書き留めます。 -
「管理」、「証明書およびシークレット」に移動して、クライアント・シークレットを追加します。シークレット値は、後のタスクで使用するためノートにとります。
タスク2: OCIアイデンティティ・ドメインでのJWTユーザー・アサーションの前提条件ステップ
-
「JWTユーザー・アサーションの前提条件」から前提条件タスクを完了します。
-
Oracle Integrationアプリケーションが必要なスコープについて検証されると、自己署名キー・ペアが生成され、機密アプリケーションが構成されます。scope値、private_key.pem、Client ID、および Client Secretを書き留めます。
ノート:機密アプリケーションで秘密キーを信頼できるパートナとしてインポートする際、自己署名キー・ペアの作成時に使用されているものと同じ
alias
を使用し、後のタスクのためにalias
を書き留めます。 -
動的グループを作成して、リソース・タイプ
function
を特定のコンパートメントからOCI Vaultサービスからシークレットを読み取れるようにします。
タスク3: OCI Vaultでのシークレットの作成
OCI Vaultの手動シークレット生成オプションを使用して、タスク1およびタスク2から収集されたシークレットを格納します。詳細は、Vaultでのシークレットの作成を参照してください。
シークレットが作成されたら、「シークレット情報」セクションからOCID値をコピーし、後のタスク用に保存します。
タスク4: func.py
ファイルの作成と構成
Microsoft Entra IDアクセス・トークンを検証し、OCI IAMアクセス・トークンをback_end_token
として生成するために、カスタム認可プロバイダとしてOCI Functionsを使用します。
-
開始するには、アプリケーションを作成します。OCIファンクションでは、アプリケーションはファンクションの論理グループです。アプリケーションに指定するプロパティによって、そのアプリケーション内のすべての機能のリソース割当ておよび構成が決まります。詳細は、アプリケーションの作成を参照してください。
-
アプリケーションが作成されたら、構成をアプリケーションに追加します。関数コードから次の項目を取得して、コードを変更せずに移植性と構成性を高めます。「キー」および「値」と入力し、「+」をクリックします。
Microsoft Entra ID、OCIアイデンティティ・ドメイン、タスク3で収集されたシークレットのOCID、タスク2から収集されたエイリアス、スコープ、およびmicrosoft Entra IDトークンが検証されるグラフ・エンドポイント
https://graph.microsoft.com/v1.0/me
からクライアントIDを追加します。 -
関数を作成するには、スタート・ガイドに移動し、「OCI Cloud Shellの起動」をクリックして、ブラウザで対話型のLinuxスタイルのクラウド・シェルを開きます。OCI Cloud Shellがロードされると、OCI Cloud Shellからカスタム認可プロバイダOracle関数をすぐに作成、開発およびデプロイできます。
-
Fn Projectコマンドライン・インタフェース(CLI)を使用して関数を作成するには、Python関数
fn init --runtime python MyCustomAuthorizer
に対して次のコマンドを入力し、[Enter]をクリックします。 -
ファンクションのボイラープレートが作成され、カスタム認可プロバイダ・ロジックを含めるように編集できるようになりました。ディレクトリをファンクション・フォルダに変更し、
func.py
ファイルを編集します。次のコード・スニペットをコピーして貼り付けます。import io import json import logging import jwt import datetime from datetime import timedelta import time import base64 from fdk import response import requests from requests.auth import HTTPBasicAuth from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend import ociVault oauth_apps = {} def initContext(context): # This method takes elements from the Application Context and from OCI Vault to create the OAuth App Clients object. if (len(oauth_apps) < 2): try: logging.getLogger().info("initContext: Initializing context") oauth_apps['idcs'] = {'introspection_endpoint': context['idcs_token_endpoint'], 'client_id': context['idcs_app_client_id'], 'scope':context['idcs_oauth_scope'], 'alias':context['alias'], 'client_secret': ociVault.getSecret(context['idcs_client_secret_ocid'])} oauth_apps['AD'] = {'token_endpoint': context['ad_endpoint'], 'client_id': context['ad_app_client_id'], 'client_secret': ociVault.getSecret(context['ad_client_secret_ocid'])} except Exception as ex: logging.getLogger().error("initContext: Failed to get config or secrets" + str(ex)) raise def getAuthContext(token, client_apps): # This method populates the Auth Context that will be returned to the gateway. auth_context = {} access_token = token[len('Bearer '):] jwtToken = json.loads(json.dumps(jwt.decode(access_token, options={"verify_signature": False}))) # Calling MSFT to validate the token try: logging.getLogger().info("getAuthContext: Calling Token Introspection function") respIntrospectToken = introspectToken(access_token, client_apps['AD']['token_endpoint'], client_apps['AD']['client_id'], client_apps['AD']['client_secret']) except Exception as ex: logging.getLogger().error("getAuthContext: Failed to introspect token" + str(ex)) raise # If AD confirmed the token valid and active, we can proceed to populate the auth context if (respIntrospectToken.status_code == 200): auth_context['active'] = True auth_context['principal'] = jwtToken['upn'] auth_context['scope'] = 'https://graph.microsoft.com/.default' # Retrieving the back-end Token backend_token = getBackEndAuthToken(client_apps['idcs']['introspection_endpoint'], client_apps['idcs']['client_id'], client_apps['idcs']['client_secret'],client_apps['idcs']['scope'],client_apps['idcs']['alias'],auth_context['principal']) # The maximum TTL for this auth is the lesser of the API Client Auth (Entra ID) and the Gateway Client Auth (OCI IAM) if (datetime.datetime.fromtimestamp(jwtToken['exp']) < (datetime.datetime.utcnow() + timedelta(seconds=backend_token['expires_in']))): auth_context['expiresAt'] = (datetime.datetime.fromtimestamp(jwtToken['exp'])).replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat() else: auth_context['expiresAt'] = (datetime.datetime.utcnow() + timedelta(seconds=backend_token['expires_in'])).replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat() # Storing the back_end_token in the context of the auth decision so we can map it to Authorization header using the request/response transformation policy auth_context['context'] = {'back_end_token': ('Bearer ' + str(backend_token['access_token']))} else: # API Client token is not active, so we will go ahead and respond with the wwwAuthenticate header auth_context['active'] = False auth_context['wwwAuthenticate'] = 'Bearer realm=\"identity.oraclecloud.com\"' return(auth_context) def introspectToken(access_token, introspection_endpoint, client_id, client_secret): # This method simply invokes the introspection api as configured in the configuration screen. # The real validation happens in the getAuthContext function. #payload = {'token': access_token} headers = {'Accept': 'application/json', 'Authorization':'Bearer '+access_token} try: logging.getLogger().info("introspectToken: Introspecting Token") resp = requests.get(introspection_endpoint, headers=headers) print(resp) except Exception as ex: logging.getLogger().error("introspectToken: Failed to introspect token" + str(ex)) raise return resp def getBackEndAuthToken(token_endpoint, client_id, client_secret, scope, alias, principal): # This method gets the token from the back-end system (ORDS in this case) try: logging.getLogger().info("getBackEndAuthToken: Getting Backend Token") print("Sub is " + principal) with open("private_key.pem", "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend() ) headers = { "alg": "RS256", "typ": "JWT", "kid": "abc" } claims = { "sub": principal, "aud": "https://identity.oraclecloud.com/", "iss": client_id, "iat": int(time.time()), "exp": int(time.time()) + 3600, # 1 hour expiration "jti": "8c7df446-bfae-40be-be09-0ab55c655436" # random number } logging.getLogger().info("Claims : ") logging.getLogger().info(claims) jwt_assertion = jwt.encode( payload=claims, key=private_key, algorithm="RS256", headers=headers ) logging.getLogger().info("Assertion is :") logging.getLogger().info(jwt_assertion) encoded = client_id + ":" + client_secret baseencoded = base64.urlsafe_b64encode(encoded.encode('UTF-8')).decode('ascii') payload = {'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'scope':scope, 'assertion':jwt_assertion} headers = {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Authorization': 'Basic %s' % baseencoded, 'Accept': '*/*'} backend_token = json.loads(requests.post(token_endpoint, data=payload, headers=headers).text) logging.getLogger().info("Backend token in generated :") logging.getLogger().info(backend_token) except Exception as ex: logging.getLogger().error("getBackEndAuthToken: Failed to get ORDS token" + str(ex)) raise return backend_token def handler(ctx, data: io.BytesIO = None): initContext(dict(ctx.Config())) logging.getLogger().info(oauth_apps) auth_context = {} try: logging.getLogger().info("handler: Started Function Execution") gateway_auth = json.loads(data.getvalue()) auth_context = getAuthContext(gateway_auth['token'], oauth_apps) if (auth_context['active']): logging.getLogger().info('Authorizer returning 200...') return response.Response( ctx, response_data=json.dumps(auth_context), status_code = 200, headers={"Content-Type": "application/json"} ) else: logging.getLogger().info('Authorizer returning 401...') return response.Response( ctx, response_data=json.dumps(str(auth_context)), status_code = 401, headers={"Content-Type": "application/json"} ) except (Exception, ValueError) as ex: logging.getLogger().info('error parsing json payload: ' + str(ex)) return response.Response( ctx, response_data=json.dumps(str(auth_context)), status_code = 500, headers={"Content-Type": "application/json"} )
-
インポート
io
、json
、logging
、datetime
、time
、base64
: I/O、JSONデータ、ロギング、日時操作およびbase64エンコーディングを処理するための標準Pythonライブラリ。jwt
: JSON Webトークン(JWT)のエンコーディングおよびデコード用のライブラリ。requests
: HTTPリクエストを行うためのライブラリ。HTTPBasicAuth
: HTTP Basic認証を処理するためのクラス。serialization
、default_backend
:暗号化操作の処理に使用される暗号化ライブラリから。ociVault
: OCI Vaultと対話するためのカスタム・モジュール。
-
グローバル変数
oauth_apps:
アプリケーション構成を格納するディクショナリ。
-
関数
-
initContext(context):
このファンクションの目的は、OCI Vaultのコンテキスト・データおよびシークレットを使用してアプリケーション構成を初期化することです。メイン・ハンドラ・メソッドの最初のものとして呼び出されるコンテキスト・ディクショナリ・オブジェクトを受信し、タスク5で説明したgetSecret()
関数を使用してOCI Vaultからシークレットを取得します。 -
getAuthContext(token, client_apps):
OCI APIゲートウェイの認証コンテキストを移入して返します。アクセス・トークンを抽出およびデコードします。introspectToken()
ファンクションをコールして、Entra IDでトークンを検証します。トークンが有効な場合は、認証コンテキストを設定し、getBackEndAuthToken()
ファンクションをコールして、OCI IAMからバックエンド・トークンを取得し、有効期限を設定します。トークンが有効でない場合は、wwwAuthenticate
ヘッダーを設定して認証エラーを示します。 -
introspectToken(access_token, introspection_endpoint, client_id, client_secret):
指定されたintrospection_endpoint
でトークンを検証します。トークンを使用してイントロスペクション・エンドポイントにGETリクエストを行います。イントロスペクションまたは検証エンドポイントからレスポンスを返します。Microsoft Entra IDにはOAuthイントロスペクションAPIエンドポイントがないため、入力として受信したトークンを使用して構成済エンドポイントを起動します。 -
getBackEndAuthToken(token_endpoint, client_id, client_secret, scope, alias, principal):
PEMファイルから秘密キーをロードします。JWTクレームを作成し、JWTアサーションにエンコードします。トークン・リクエストのペイロードおよびヘッダーを準備します。バックエンド・トークンを取得するためにトークン・エンドポイントにPOSTリクエストを行い、バックエンド・トークンをgetAuthContext()
関数に返します。 -
handler(ctx, data: io.BytesIO = None):
ファンクションの実行を処理するメイン・ファンクション。initContext()
関数を使用してOAuthコンテキストを初期化し、getAuthContext()
関数をコールして認証コンテキストを取得します。トークンが有効な場合は 200応答を返し、それ以外の場合は 401応答を返します。エラーの場合、500応答を記録して返します。
-
-
タスク5: ociVault.py
ファイルの作成と構成
同じフォルダにociVault.py
ファイルを作成し、次のコード・スニペットを貼り付けます。このユーティリティ関数は、OCI Vaultサービスからシークレットを読み取ります。
# Utility Function to get secrets from OCI Vault
import logging
import oci
import base64
def getSecret(ocid):
signer = oci.auth.signers.get_resource_principals_signer()
try:
client = oci.secrets.SecretsClient({}, signer=signer)
secret_content = client.get_secret_bundle(ocid).data.secret_bundle_content.content.encode('utf-8')
decrypted_secret_content = base64.b64decode(secret_content).decode('utf-8')
except Exception as ex:
logging.getLogger().error("getSecret: Failed to get Secret" + ex)
print("Error [getSecret]: failed to retrieve", ex, flush=True)
raise
return decrypted_secret_content
ノート:タスク2の
private_key.pem
ファイルを同じフォルダに保持します。
タスク5: 関数のテスト
ファンクションをテストするには、ファンクションをデプロイし、Microsoft Entra IDトークンを入力として渡して起動する必要があります。
-
関数フォルダに移動し、次のコマンド
fn -v deploy --app MyCustomAuthorizer
を実行してデプロイします。Fn ProjectのCLIコマンドは、ファンクションを構築し、OCI Functionsアプリケーションに同じものをデプロイします。ノート: ファンクション・アプリケーションをデプロイする前に、
requirements.txt
ファイルにfdk>=0.1.74
、requests
、oci
、pyjwt
、serialization
を含めます。 -
Postmanクライアントを使用して、OAuth 2.0 ROPCフローを使用してMicrosoft Entra IDからアクセス・トークンを生成します。
-
アクセス・トークンを書き留めて、OCI関数をテストするための入力として渡される
payload.json
を生成します。JSONファイルは同じファンクション・ディレクトリに保管してください。 -
ペイロードを保存したら、次のコマンドを実行して、OCI API Gateway (
cat payload.json | fn invoke <AppName> <function name>
)を介して起動されるファンクションの実行を模倣できます(次の図を参照)。Microsoft Entra IDトークンが有効な場合は、次のイメージに示すようにレスポンスが表示され、コンテキスト構造の
back_end_token
値にOCI IAMトークン値が表示されます。
タスク6: OCI APIゲートウェイの構成
OCI API Gatewayは、迅速なAPIデプロイメントからライフサイクル管理、バックエンド・サービス統合まで、一連のサービスを提供する、完全に管理されたスケーラブルなクラウドネイティブAPI管理プラットフォームです。APIゲートウェイを利用して、Microsoft Entra IDなどの外部アイデンティティ・プロバイダを使用してOracle Integrationの認可を仲介します。
まず、新しいAPIゲートウェイを作成してから、APIゲートウェイに新しいデプロイメントを作成します。
-
「開発者サービス」、「API管理」および「ゲートウェイ」に移動します。次の情報を入力して、「ゲートウェイの作成」をクリックします。
-
「ゲートウェイの詳細」ページで、「デプロイメントの作成」をクリックし、APIデプロイメントの次の必須情報を入力します。
- 名前:名前を入力します。
- パス接頭辞:パスを定義します。
- コンパートメント: APIデプロイメントに適したコンパートメントを選択します。
-
認証ポリシーの詳細を追加します。ここでは、カスタム認可プロバイダとして起動されるOCI関数を構成します。タスク4で作成した機能を選択します。
-
「ルート」ページで、バックエンド・サービスへのAPIルーティングを構成します。このチュートリアルでは、Oracle Integrationエンドポイントへのルーティングを定義します。
-
「ルート・リクエスト・ポリシーの表示」をクリックします。ここでは、ユーザーがOCI Functionsレスポンスからリクエストの認証ヘッダーへの認証トークンのスワップを実行します。
このステップでは、バックエンド・アイデンティティ・プロバイダに基づいてバックエンド・サービスの認証トークンを設定します。このシナリオでは、カスタム認可プロバイダOCI関数から受信したOCI IAMのベアラー・トークンを設定します。ここでは、認可ヘッダーを値
${request.auth[back_end_token]}
でオーバーライドするように構成します。back_end_token
は、Oracleファンクションのレスポンス構造のコンテキストの一部です。カスタム認可プロバイダOCI関数の完了後に、この式が正常に評価されることを確認します。 -
構成を正常に確認した後、「変更の保存」をクリックしてデプロイメントを保存し、デプロイメントの状態が「アクティブ」に変わるまで待機します。
APIデプロイメントをアクティブ化した後、「デプロイメント情報」セクションから「エンドポイント」(ベースURL)をコピーします。このURLは、ビジネス・プロセスまたはアプリケーションがMicrosoft Entra ID Bearerトークンを使用してOracle Integrationエンドポイントを起動するデプロイメントのエンドポイントとして機能します。次のタスクではベースURLを使用します。
タスク7: APIのテスト
まず、Postmanクライアントを使用してMicrosoft Entra IDからアクセス・トークンを取得します。ROPCフローを使用して、アクセス・トークンに必要なアイデンティティ情報が含まれていることを確認します。
-
APIゲートウェイからのAPIの起動時と同じように、アクセス・トークンをコピーします。
-
次の図に示すように、APIゲートウェイおよびOracle Integrationエンドポイントからタスク6でコピーされたベース・エンドポイントURLを組み合せた新しいRESTリクエストを作成します。リクエスト・ヘッダーでbearerトークンを使用します。
-
「送信」をクリックしてAPIリクエストを起動すると、Oracle Integrationが実行され、正常に出力されます。
次のステップ
Microsoft Entra IDからOAuthトークンを使用してOracle API GatewayでAPIを正常に起動し、Oracle Integration RESTトリガー・フローからレスポンスを受信しました。この統合は、異なるクラウド・ベンダー間でデジタル・サービスを接続するお客様にとって非常に重要です。
関連リンク
確認
- 著者 - Gautam Mishra (プリンシパル・クラウド・アーキテクト)
その他の学習リソース
docs.oracle.com/learnの他のラボを確認するか、Oracle Learning YouTubeチャネルで無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスしてOracle Learning Explorerになります。
製品ドキュメントは、Oracle Help Centerを参照してください。
Securely Access Oracle Integration using Access Tokens from Microsoft Entra ID
G13115-01
August 2024