ノート:
- このチュートリアルでは、Oracle Cloudへのアクセスが必要です。無料アカウントにサインアップするには、Oracle Cloud Infrastructure Free Tierの開始を参照してください。
- Oracle Cloud Infrastructureの資格証明、テナンシおよびコンパートメントに例の値を使用します。演習を終える際は、これらの値をクラウド環境に固有の値に置き換えてください。
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日ごとに資格証明をローテーションすることをお薦めします。
ノート:このソリューションは、デフォルトのアイデンティティ・ドメインについてテストされています。
目的
-
Oracle Cloud Guardの問題を修正することで、自動化により、Oracle Cloud Infrastructure (OCI)認証トークン、APIキー、顧客秘密キーおよびOCIコンソールのパスワードをローテーションします。OCI IAM資格証明の自動ローテーションには、次のOracle Cloud Guardの問題が使用されます。
- APIキーが古すぎます
- IAM認証トークンが古すぎます
- IAM顧客秘密キーが古すぎます
- パスワードが古すぎます
前提条件
OCI IAM管理者は、次を作成する必要があります:
-
OCI Functionsの動的グループおよびポリシー: 問題の呼出し、修正および電子メール通知の送信を行います。
-
動的グループ:ファンクション・コンパートメントの動的グループを作成します。詳細は、「動的グループの作成」を参照してください。
# Replace OCID for function compartment All {resource.type = 'fnfunc', resource.compartment.id = '<function-compartment>'} Example: All {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaaaanovmfmmnonjjyxeq4jyghszj2eczlrkgj5svnxrt...'}
-
ポリシー:ファンクションに動的グループを割り当てるポリシーを作成します。詳細は、ポリシーの開始を参照してください。
# Replace dynamic-group-name, function-compartment and OCID of vault secret for OCI function Allow dynamic-group <dynamic-group-name> to inspect compartments in tenancy Allow dynamic-group <dynamic-group-name> to inspect users in tenancy Allow dynamic-group <dynamic-group-name> to manage users in tenancy where any {request.permission = 'USER_UPDATE', request.permission = 'USER_AUTHTOKEN_SET', request.permission = 'USER_AUTHTOKEN_REMOVE', request.permission = 'USER_SECRETKEY_ADD', request.permission = 'USER_SECRETKEY_REMOVE', request.permission = 'USER_UIPASS_SET', request.permission = 'USER_APIKEY_ADD', request.permission = 'USER_APIKEY_REMOVE'} Allow dynamic-group <dynamic-group-name> to read repos in compartment <function-compartment> Allow dynamic-group <dynamic-group-name> to use secret-family in compartment <vault-compartment> where target.secret.id='<ocid of OCI vault secret to store rotated OCI secrets>' Allow dynamic-group <dynamic-group-name> to use ons-topics in tenancy
-
-
開発者がシークレットを作成し、ファンクションをデプロイするためのコンパートメント、グループおよびポリシー。
# Replace group-name as per your tenancy Allow group <group-name> to manage repos in compartment <function-compartment> Allow group <group-name> to manage vaults in compartment <function-compartment> Allow group <group-name> to manage keys in compartment <function-compartment> Allow group <group-name> to manage secret-family in compartment <function-compartment> Allow group <group-name> to manage functions-family in compartment <function-compartment> Allow group <group-name> to use cloud-shell in tenancy Allow group <group-name> to use virtual-network-family in compartment <network-compartment> Allow group <group-name> to read objectstorage-namespaces in tenancy
-
SecOpsチームが電子メール通知を受信するためのOCI通知トピック。
-
Oracle Cloud Infrastructure Secrets in Vault to store rotated OCI IAM credentials created by automation.
Note : Make sure you have copied existing OCI IAM credentials for Oracle Cloud Infrastructure Secrets in Vault before running this automation for the first time.
タスク1: OCIファンクションの作成およびデプロイ
-
OCIコンソールにログインし、上部ナビゲーションから「クラウド・シェル」をクリックします。
ノート:独自のIDEツールを使用して、ファンクションを作成およびデプロイすることもできます。
-
クラウド・シェルからFnプロジェクトCLIを使用してファンクションを作成します。詳細は、Helloworldファンクションの作成、デプロイおよび呼出しを参照してください。
fn init --runtime python <function-name> Example: fn init --runtime python rotatecred-func
-
ディレクトリを新しく作成されたディレクトリに変更します。
-
次のコマンドを使用して、ファンクションをデプロイするアプリケーションを作成します。
# 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....."]'
-
既存のコンテンツを上書きして、
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"})
-
次に示すように、
requirements.txt
を更新します。fdk>=0.1.59 oci pycryptodomex
-
次のコマンドを実行して、ファンクションをデプロイします。
fn -v deploy --app <app-name> Example: fn -v deploy --app rotatecredapp
-
次のコマンドを実行して、構成キーおよび値の関数構成を追加します。
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: イベント・ルールの作成
-
OCIコンソールに移動し、「監視および管理」をクリックします。
-
「イベント・サービス」で、「ルール」および「ルールの作成」をクリックします。
-
「ルールの作成」ページで、ルールの「名前」およびルールの「説明」を入力します。
-
「ルール条件」セクションで、次の情報を入力して、ファンクションをトリガーするイベント・タイプおよびアクションを指定します。
- 条件:
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の問題の修正
-
OCIコンソールに移動し、「アイデンティティとセキュリティ」をクリックします。
-
「クラウド・ガード」で、「問題」をクリックします。
-
自動ローテーションでサポートされている問題の1つをクリックします。
-
「解決済としてマーク」をクリックし、次の形式で「コメント」セクションに次の情報を入力します。次の情報をカンマ(、)で区切って、組織プロセスに従って追加情報を追加できます。
-
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の詳細および追加情報を含む問題解決電子メール通知を受信します。
関連リンク
承認
-
著者 - Dipesh Kumar Rathod(インフラストラクチャ、マスター・プリンシパル・クラウド・アーキテクト)
-
貢献者 - Bhanu Prakash Lohumi (インフラストラクチャ担当シニア・クラウド・エンジニア)
その他の学習リソース
docs.oracle.com/learnの他のラボをご覧いただくか、Oracle Learning YouTubeチャネルで無料のラーニング・コンテンツにアクセスしてください。また、education.oracle.com/learning-explorerにアクセスして、Oracle Learning Explorerになります。
製品ドキュメントは、Oracle Help Centerを参照してください。
Enable Auto Rotation of Oracle Cloud Infrastructure Identity and Access Management Credentials
F93266-01
February 2024
Copyright © 2024, Oracle and/or its affiliates.