주:
- 이 사용지침서에서는 Oracle Cloud에 액세스해야 합니다. 무료 계정에 등록하려면 Oracle Cloud Infrastructure Free Tier 시작하기를 참조하십시오.
- Oracle Cloud Infrastructure 인증서, 테넌시 및 구획에 대한 예제 값을 사용합니다. 실습을 마칠 때는 이러한 값을 클라우드 환경과 관련된 값으로 대체하십시오.
Oracle Cloud Infrastructure Identity and Access Management 인증서 자동 교체 사용
소개
이 사용지침서에서는 API 키, 인증 토큰, 고객 암호 키 및 OCI 콘솔 로그인 비밀번호인 OCI IAM(Oracle Cloud Infrastructure Identity and Access Management) 인증서를 자동 교체하는 데 도움이 됩니다. Oracle Cloud Guard 문제 해결 및 OCI 통지 서비스를 기반으로 합니다. 또한 기본 응답기 규칙의 차이를 충족하여 OCI IAM 인증서를 교체합니다.
Oracle Cloud Guard는 정책에 정의된 규칙을 기반으로 문제를 감지합니다. 규칙이 충족되면 문제가 발생합니다.
보안 모범 사례이며 CIS OCI Foundations(Center for Internet Security Oracle Cloud Infrastructure Foundations) 벤치마크에서 90일마다 인증서를 교체하는 것이 좋습니다.
주: 이 솔루션은 기본 ID 도메인에 대해 테스트되었습니다.
목표
-
Oracle Cloud Guard 문제를 해결하여 자동화를 통해 OCI(Oracle Cloud Infrastructure) 인증 토큰, API 키, 고객 암호 키 및 OCI 콘솔 비밀번호를 교체합니다. 다음 Oracle Cloud Guard 문제는 OCI IAM 인증서 자동 교체에 사용됩니다.
- API 키가 너무 오래되었습니다.
- IAM 인증 토큰이 너무 오래되었습니다.
- IAM 고객 암호 키가 너무 오래되었습니다.
- 비밀번호가 너무 오래되었습니다.
필요 조건
OCI IAM 관리자는 다음을 생성해야 합니다.
-
OCI 함수에 대한 동적 그룹 및 정책은 문제를 호출하고 해결하며 전자메일 통지를 전송합니다.
-
동적 그룹: 함수 구획에 대한 동적 그룹을 생성합니다. 자세한 내용은 동적 그룹 생성을 참조하십시오.
# 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 - 자동화로 생성된 교체된 OCI IAM 자격 증명을 저장합니다.
참고: 이 자동화를 처음으로 실행하기 전에 Oracle Cloud Infrastructure Secrets in Vault에 대한 기존 OCI IAM 인증서를 복사했는지 확인하십시오.
작업 1: OCI 함수 생성 및 배치
-
OCI 콘솔에 로그인하고 위쪽 탐색에서 Cloud Shell을 누릅니다.
주: 고유의 IDE 툴을 사용하여 함수를 생성하고 배치할 수도 있습니다.
-
Cloud Shell에서 Fn 프로젝트 CLI를 사용하여 함수를 생성합니다. 자세한 내용은 Creating, Deploying, and Invoking a Helloworld Function를 참조하십시오.
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
: 전자메일 통지 수신을 위해 통지 토픽의 OCID(Oracle Cloud 식별자)를 사용합니다.
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 콘솔로 이동하여 ID 및 보안을 누릅니다.
-
Cloud Guard에서 문제를 누릅니다.
-
자동 회전에 대해 지원되는 문제 중 하나를 클릭합니다.
-
해결됨으로 표시를 누르고 다음 형식에 따라 설명 섹션에 다음 정보를 입력합니다. 쉼표(,)로 구분된 다음 정보와 함께 조직 프로세스에 따라 다른 정보를 추가할 수 있습니다.
-
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
F93267-01
February 2024
Copyright © 2024, Oracle and/or its affiliates.