Nota
- Questa esercitazione richiede l'accesso a Oracle Cloud. Per iscriverti a un account gratuito, consulta Inizia a utilizzare Oracle Cloud Infrastructure Free Tier.
- Utilizza valori di esempio per le credenziali, la tenancy e i compartimenti di Oracle Cloud Infrastructure. Al termine del laboratorio, sostituisci questi valori con quelli specifici del tuo ambiente cloud.
Abilita rotazione automatica delle credenziali di Oracle Cloud Infrastructure Identity and Access Management
Introduzione
Questa esercitazione consente di ruotare automaticamente le credenziali di Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) costituite da chiave API, token di autenticazione, chiavi segrete del cliente e password di login della console OCI. Si basa sulla risoluzione dei problemi di Oracle Cloud Guard e sul servizio di notifiche OCI. Inoltre, colma il divario delle regole del rispondente predefinite per ruotare le credenziali IAM OCI.
Oracle Cloud Guard rileva i problemi in base alle regole definite nei criteri. Una volta soddisfatta, una regola crea un problema.
Si tratta di una best practice per la sicurezza e consigliata dal benchmark The Center for Internet Security Oracle Cloud Infrastructure Foundations (CIS OCI Foundations) per ruotare le credenziali ogni 90 giorni.
Nota: questa soluzione è stata sottoposta a test per un dominio di Identity predefinito.
Obiettivi
-
Ruota il token di autenticazione Oracle Cloud Infrastructure (OCI), la chiave API, la chiave segreta del cliente e la password della console OCI attraverso l'automazione risolvendo il problema di Oracle Cloud Guard. I problemi di Oracle Cloud Guard riportati di seguito vengono utilizzati per la rotazione automatica delle credenziali IAM OCI.
- La chiave API è troppo vecchia
- Il token di autenticazione IAM è troppo vecchio
- La chiave segreta del cliente IAM è troppo vecchia
- La password è troppo vecchia
Prerequisiti
L'amministratore IAM OCI deve creare:
-
Gruppo dinamico e criteri per le funzioni OCI per richiamare, risolvere il problema e inviare notifiche di posta elettronica.
-
Gruppo dinamico: crea un gruppo dinamico per il compartimento funzioni. Per ulteriori informazioni, vedere Creazione di un gruppo dinamico.
# 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...'}
-
Criteri: creare criteri per assegnare un gruppo dinamico alla funzione. Per ulteriori informazioni, consulta la guida introduttiva ai criteri.
# 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
-
-
Compartimento, gruppo e criteri per consentire allo sviluppatore di creare segreti e distribuire la funzione.
# 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
-
Argomento delle notifiche OCI per il team SecOps per ricevere notifiche via e-mail.
-
I segreti di Oracle Cloud Infrastructure Secrets in Vault per memorizzare le credenziali IAM OCI ruotate create dall'automazione.
Nota: prima di eseguire questa automazione per la prima volta, assicurarsi di aver copiato le credenziali IAM OCI esistenti per i segreti di Oracle Cloud Infrastructure Secrets in Vault.
Task 1: Creare e distribuire le funzioni OCI
-
Eseguire il login a OCI Console e fare clic su Cloud Shell dalla navigazione superiore.
Nota: è inoltre possibile utilizzare il proprio strumento IDE per creare e distribuire una funzione.
-
Creare una funzione utilizzando l'interfaccia CLI del progetto Fn dalla shell cloud shell. Per ulteriori informazioni, vedere Creazione, distribuzione e richiamo di una funzione Helloworld.
fn init --runtime python <function-name> Example: fn init --runtime python rotatecred-func
-
Spostarsi nella directory appena creata.
-
Creare un'applicazione per distribuire la funzione utilizzando il comando seguente.
# 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....."]'
-
Copiare e incollare il seguente script in
func.py
sovrascrivendo il contenuto esistente.# 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"})
-
Aggiornare
requirements.txt
come mostrato di seguito.fdk>=0.1.59 oci pycryptodomex
-
Per distribuire la funzione, eseguire il comando riportato di seguito.
fn -v deploy --app <app-name> Example: fn -v deploy --app rotatecredapp
-
Eseguire il comando seguente per aggiungere la configurazione della funzione per chiave e valore di configurazione.
ons_topic
: utilizzare l'OCID (Oracle Cloud Identifier) dell'argomento di notifica per ricevere la notifica tramite posta elettronica.
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
Task 2: creazione di una regola evento
-
Andare a OCI Console e fare clic su Osservabilità e gestione.
-
In Servizio eventi, fare clic su Regole e Crea regola.
-
Nella pagina Crea regola, inserire il nome della regola e la descrizione delle operazioni eseguite dalla regola.
-
Nella sezione Condizioni regola, immettere le informazioni riportate di seguito per specificare il tipo di evento e l'azione per attivare la funzione.
- Condizione:
Event Type
. - Nome servizio:
Cloud Guard
. - Tipo di evento:
Remediated-Problem
. - Nome attributo:
ProblemRecommendation
. - Valori attributi:
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
.
L'immagine seguente mostra un esempio di evento di risoluzione del problema di Oracle Cloud Guard.
- Condizione:
Task 3: risolvere il problema di Oracle Cloud Guard
-
Andare a OCI Console e fare clic su Identità e sicurezza.
-
In Cloud Guard, fare clic su Problemi.
-
Fare clic su uno dei problemi supportati per la rotazione automatica.
-
Fare clic su Contrassegna come risolto e immettere le informazioni riportate di seguito nella sezione Commento in base al seguente formato. È possibile aggiungere ulteriori informazioni in base al processo dell'organizzazione insieme alle seguenti informazioni separate da virgole (,).
-
La chiave segreta del cliente IAM è troppo vecchia.
accesskey_secret_ocid:<OCID of access key secret>,secretkey_secret_ocid:<OCID of secret key secret>,<additional comments>
-
La chiave API è troppo vecchia.
api_secret_ocid:<OCID of api key secret>,<additional comments>
-
Il token di autenticazione IAM è troppo vecchio.
auth_secret_ocid:<OCID of auth token secret>,<additional comments>
-
La password è troppo vecchia.
Nota:
- Non sono necessarie informazioni da includere nei commenti per questo problema.
- La password deve essere reimpostata dal singolo utente facendo clic su Password dimenticata al login successivo. Per ricevere le notifiche e-mail, l'utente deve disporre di un indirizzo e-mail valido.
-
Task 4: Convalida una nuova credenziale IAM OCI e notifica e-mail
Si riceverà una notifica di posta elettronica di risoluzione dei problemi con i dettagli dell'OCID segreto ruotato e informazioni aggiuntive.
Collegamenti correlati
Conferme
-
Autore - Dipesh Kumar Rathod (Master Principal Cloud Architect, Infrastruttura)
-
Contributor - Bhanu Prakash Lohumi (Senior Cloud Engineer, Infrastructure)
Altre risorse di apprendimento
Esplora altri laboratori su docs.oracle.com/learn o accedi a più contenuti gratuiti sulla formazione su Oracle Learning YouTube channel. Inoltre, visita education.oracle.com/learning-explorer per diventare un Oracle Learning Explorer.
Per la documentazione del prodotto, visita l'Oracle Help Center.
Enable Auto Rotation of Oracle Cloud Infrastructure Identity and Access Management Credentials
F93265-01
February 2024
Copyright © 2024, Oracle and/or its affiliates.