ノート:

Oracle Cloud Infrastructure Identity and Access Management資格証明の自動ローテーションの有効化

イントロダクション

このチュートリアルは、APIキー、認証トークン、顧客秘密キーおよびOCIコンソール・ログイン・パスワードであるOracle Cloud Infrastructure Identity and Access Management (OCI IAM)資格証明の自動ローテーションに役立ちます。これは、Oracle Cloud Guardの問題の修正とOCI Notificationsサービスに基づいています。また、OCI IAM資格証明をローテーションするためのデフォルト・レスポンダ・ルールのギャップも果たします。

Oracle Cloud Guardは、ポリシーで定義されたルールに基づいて問題を検出します。ルールが満たされると、問題が作成されます。

これはセキュリティのベスト・プラクティスであり、Center for Internet Security Oracle Cloud Infrastructure Foundations (CIS OCI Foundations)ベンチマークで、90日ごとに資格証明をローテーションすることをお薦めします。

ノート:このソリューションは、デフォルトのアイデンティティ・ドメインについてテストされています。

目的

前提条件

OCI IAM管理者は、次を作成する必要があります:

タスク1: OCIファンクションの作成およびデプロイ

  1. OCIコンソールにログインし、上部ナビゲーションから「クラウド・シェル」をクリックします。

    ノート:独自のIDEツールを使用して、ファンクションを作成およびデプロイすることもできます。

  2. クラウド・シェルからFnプロジェクトCLIを使用してファンクションを作成します。詳細は、Helloworldファンクションの作成、デプロイおよび呼出しを参照してください。

    fn init --runtime python <function-name>
    
    Example: fn init --runtime python rotatecred-func
    
  3. ディレクトリを新しく作成されたディレクトリに変更します。

  4. 次のコマンドを使用して、ファンクションをデプロイするアプリケーションを作成します。

    # Specify the OCID of subnet
    fn create app <app-name> --annotation oracle.com/oci/subnetIds='["<subnet OCID>"]'
    
    Example:  fn create app rotatecredapp --annotation oracle.com/oci/subnetIds='["ocid1.subnet.oc1.ap-mumbai-1.aaaaaaaabitp32dkyox37qa3tk3evl2nxivwb....."]'
    
  5. 既存のコンテンツを上書きして、func.pyの次のスクリプトをコピーして貼り付けます。

    # python script for auto rotation of OCI IAM credentials
    import io
    import json
    import logging
    import oci
    import base64
    from fdk import response
    from Cryptodome.PublicKey import RSA
    
    # Get Resource Principal Credentials
    signer = oci.auth.signers.get_resource_principals_signer()
    
    # Initialize client
    identity_client = oci.identity.IdentityClient(config={}, signer=signer)
    onsclient = oci.ons.NotificationDataPlaneClient(config={}, signer=signer)
    vault_client = oci.vault.VaultsClient(config={}, signer=signer)
    
    # Get tenancy id and name
    tenancy_data = identity_client.get_tenancy(tenancy_id=signer.tenancy_id).data
    t_name = str(tenancy_data.name)
    t_id = signer.tenancy_id
    
    # Get secret OCID from comments
    def get_secret_ocids(comments_items,find_name):
       secret_ocid = ""
       for comment in comments_items:
          if comment.split(":")[0] == find_name:
                secret_ocid = comment.split(":")[1]
       return secret_ocid
    
    # Function to store secret in OCI vault
    def update_secret(vault_client,secret_id,new_value):
       # Base64 encode
       new_token_ascii = new_value.encode("ascii")
       base64_bytes = base64.b64encode(new_token_ascii)
       base64_string = base64_bytes.decode("ascii")
    
       # Create new version of secret
       vault_client.update_secret(secret_id=secret_id,update_secret_details=oci.vault.models.UpdateSecretDetails(secret_content=oci.vault.models.Base64SecretContentDetails(content_type="BASE64", content=base64_string)))
    
    def handler(ctx, data: io.BytesIO=None):
       try:
          cfg = ctx.Config()
          ons_topic = cfg["ons_topic"]
          body = json.loads(data.getvalue())
    
          # Get common parameters values
          e_time = str(body["eventTime"]).lstrip()
          problem_name = str(body["data"]["additionalDetails"]["problemName"]).lstrip()
          status = "NOT RESOLVED"
          resource_name = str(body["data"]["resourceName"]).lstrip()
          user_ocid = str(body["data"]["additionalDetails"]["problemAdditionalDetails"]["User OCID"]).lstrip()
          target_resource_name = str(body["data"]["additionalDetails"]["resourceName"]).lstrip()
          target_resource_id = str(body["data"]["additionalDetails"]["resourceId"]).lstrip()
          risk_level = str(body["data"]["additionalDetails"]["riskLevel"]).lstrip()
          comments = str(body["data"]["additionalDetails"]["problemAdditionalDetails"]["comments"]).lstrip()
          comments_items = comments.split(",")
          additional_details = "\r\r\nAction : Closure comments was not in required format hence, no action by automation."
    
          try:
                # Check Problem Type
                if problem_name == "PASSWORD_TOO_OLD":
                   identity_client.create_or_reset_ui_password(user_id=user_ocid)
                   additional_details = "\r\r\nAction : Your password has been reset by the System Administrator as per password policy rotation. Please set new password by clicking on forgot password from OCI console. "
                   status = "RESOLVED"
    
                elif problem_name == "AUTH_TOKEN_TOO_OLD":
                   auth_secret_ocid = get_secret_ocids(comments_items,"auth_secret_ocid")
                   if auth_secret_ocid != "":
                      # Delete existing auth token
                      identity_client.delete_auth_token(user_id=user_ocid, auth_token_id=target_resource_id)
                      # Create new auth token
                      create_auth_token_response = identity_client.create_auth_token(
                      create_auth_token_details=oci.identity.models.CreateAuthTokenDetails(description=target_resource_name),user_id=user_ocid).data
                      new_value = create_auth_token_response.token
                      # Store new auth token in vault secret
                      update_secret(vault_client,auth_secret_ocid,new_value)
                      additional_details = '\r\nAuth Token - Secret OCID : ' + auth_secret_ocid
                      status = "RESOLVED"
    
                elif problem_name == "SECRET_KEY_TOO_OLD":
                   access_id_secret_ocid = get_secret_ocids(comments_items, "accesskey_secret_ocid")
                   secret_key_secret_ocid = get_secret_ocids(comments_items, "secretkey_secret_ocid")
                   if access_id_secret_ocid != "" and secret_key_secret_ocid != "":
                      # Delete existing customer secrete key
                      delete_secret_key_response = identity_client.delete_customer_secret_key(user_ocid, target_resource_id).data
                      # Create new customer secret key
                      create_customer_secret_key_response = identity_client.create_customer_secret_key(create_customer_secret_key_details=oci.identity.models.CreateCustomerSecretKeyDetails(display_name=target_resource_name),user_id=user_ocid).data
                      new_secret_key = str(create_customer_secret_key_response.key)
                      new_access_key_id = str(create_customer_secret_key_response.id)
                      # Store new customer secret key in vault secret
                      update_secret(vault_client,secret_key_secret_ocid,new_secret_key)
                      update_secret(vault_client,access_id_secret_ocid,new_access_key_id)
                      additional_details = '\r\nAccess Key - Secret OCID : ' + access_id_secret_ocid + \
                               '\r\nSecret Key - Secret OCID : ' + secret_key_secret_ocid
                      status = "RESOLVED"
    
                elif problem_name == "API_KEY_TOO_OLD":
                   key_fingerprint = target_resource_id.split("/")[2]
                   api_secret_ocid = get_secret_ocids(comments_items,"api_secret_ocid")
                   if api_secret_ocid != "":
                      key = RSA.generate(2048)
                      key_private = key.exportKey()
                      pubkey = key.publickey()
                      key_public = pubkey.exportKey()
                      # Delete existing API key
                      delete_api_key_response = identity_client.delete_api_key(user_id=user_ocid,fingerprint=key_fingerprint)
                      # Upload new public API key in OCI for the user
                      upload_api_key_response = identity_client.upload_api_key(user_id=user_ocid,
                                                                               create_api_key_details=oci.identity.models.CreateApiKeyDetails(
                                                                                     key=key_public.decode()))
                      # Store content of new private key in vault secret
                      update_secret(vault_client,api_secret_ocid,key_private.decode())
                      additional_details = '\r\nSecret OCID for private API key : ' + api_secret_ocid
                      status = "RESOLVED"
          except Exception as e:
                additional_details = '\r\r\n Error: '+ str(e)
    
          # Message Body Customization, it can be updated as per need
          line_head = 'Oracle Cloud Notification' + '\n====================='
          message_body = line_head + \
                         '\r\r\nProblem Name : ' + problem_name + \
                         '\r\r\nRisk Level : ' + risk_level + \
                         '\r\nEvent Time : ' + e_time + \
                         '\r\nTenancy Name : ' + t_name + \
                         '\r\nTenancy ID : ' + t_id + \
                         '\r\r\nAdditional Details : ' + '\n-------------------------' \
                         '\r\nResource Name : ' + target_resource_name + \
                         '\r\nResource ID : ' + target_resource_id + \
                         '\r\nResource User OCID : ' + user_ocid + ' ' + additional_details
    
          # Message Title
          message_title = 'Problem : ' + resource_name + ' | ' + status +' by automation '
    
          # Message Detail
          message_details = oci.ons.models.MessageDetails(body=message_body, title=message_title)
    
          # Publish message to ONS
          onsclient.publish_message(ons_topic, message_details)
    
       except (Exception, ValueError) as ex:
          logging.getLogger().info('error parsing json payload: ' + str(ex))
    
       return response.Response(ctx, response_data=json.dumps({"message": "success"}),headers={"Content-Type": "application/json"})
    
  6. 次に示すように、requirements.txtを更新します。

    fdk>=0.1.59
    oci
    pycryptodomex
    
  7. 次のコマンドを実行して、ファンクションをデプロイします。

    fn -v deploy --app <app-name>
    
    Example: fn -v deploy --app rotatecredapp
    
  8. 次のコマンドを実行して、構成キーおよび値の関数構成を追加します。

    • ons_topic: 電子メール通知の受信には、通知トピックのOracle Cloud Identifier (OCID)を使用します。
    fn config function <app-name> <function-name> <config-key> <config-value>
    
    Example: fn config function rotatecredapp rotatecred-func ons_topic ocid1.onstopic.oc1.ap-mumbai-1.aaaaaaaau3onlufcfz.......kae26637zovwd7q
    

タスク2: イベント・ルールの作成

  1. OCIコンソールに移動し、「監視および管理」をクリックします。

  2. 「イベント・サービス」で、「ルール」および「ルールの作成」をクリックします。

  3. 「ルールの作成」ページで、ルールの「名前」およびルールの「説明」を入力します。

  4. 「ルール条件」セクションで、次の情報を入力して、ファンクションをトリガーするイベント・タイプおよびアクションを指定します。

    • 条件: Event Type
    • サービス名: Cloud Guard
    • イベント・タイプ: Remediated-Problem
    • 属性名: ProblemRecommendation
    • 属性値:
      • Rotate IAM Console password regularly, at least every 90 days.,
      • Rotate IAM Auth token regularly, at least every 90 days.,
      • Rotate IAM Customer secret keys regularly, at least every 90 days.,
      • Rotate API keys regularly, at least every 90 days.

    次の図は、Oracle Cloud Guardの問題修正イベントの例です。

    イメージ

タスク3: Oracle Cloud Guardの問題の修正

  1. OCIコンソールに移動し、「アイデンティティとセキュリティ」をクリックします。

  2. 「クラウド・ガード」で、「問題」をクリックします。

  3. 自動ローテーションでサポートされている問題の1つをクリックします。

  4. 「解決済としてマーク」をクリックし、次の形式で「コメント」セクションに次の情報を入力します。次の情報をカンマ(、)で区切って、組織プロセスに従って追加情報を追加できます。

    • IAM顧客秘密キーが古すぎます

      accesskey_secret_ocid:<OCID of access key secret>,secretkey_secret_ocid:<OCID of secret key secret>,<additional comments>

      イメージ

    • APIキーが古すぎます

      api_secret_ocid:<OCID of api key secret>,<additional comments>

      イメージ

    • IAM認証トークンが古すぎます

      auth_secret_ocid:<OCID of auth token secret>,<additional comments>

      イメージ

    • パスワードが古すぎます

      ノート:

      • この問題のコメントに含める必要のある情報はありません。
      • パスワードは、次回ログイン時に「パスワードを忘れた場合」をクリックして、個々のユーザーがリセットする必要があります。ユーザーには、電子メール通知を受信するための有効な電子メール・アドレスが必要です。

タスク4: 新しいOCI IAM資格証明および電子メール通知の検証

ローテーションされたシークレットOCIDの詳細および追加情報を含む問題解決電子メール通知を受信します。

イメージ

承認

その他の学習リソース

docs.oracle.com/learnの他のラボをご覧いただくか、Oracle Learning YouTubeチャネルで無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスして、Oracle Learning Explorerになります。

製品ドキュメントは、Oracle Help Centerを参照してください。