Note:
- Este tutorial requiere acceso a Oracle Cloud. Para registrarse en una cuenta gratuita, consulte Introducción a la capa gratuita de Oracle Cloud Infrastructure.
- Utiliza valores de ejemplo para credenciales, arrendamiento y compartimentos de Oracle Cloud Infrastructure. Al completar el laboratorio, sustituya estos valores por otros específicos de su entorno en la nube.
Activación de la rotación automática de credenciales de Oracle Cloud Infrastructure Identity and Access Management
Introducción
Este tutorial ayuda a rotar automáticamente las credenciales de Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) que son clave de API, token de autenticación, claves secretas de cliente y contraseñas de conexión de la consola de OCI. Se basa en la solución de problemas de Oracle Cloud Guard y en el servicio OCI Notifications. También cumple el intervalo de reglas de responsable de respuesta por defecto para rotar las credenciales de OCI IAM.
Oracle Cloud Guard detecta problemas basados en reglas definidas en las políticas. Una vez que se cumple una regla, se crea un problema.
Es una práctica recomendada de seguridad y recomendada por The Center for Internet Security Oracle Cloud Infrastructure Foundations (CIS OCI Foundations) Benchmark para rotar las credenciales cada 90 días.
Nota: Esta solución se ha probado para un dominio de identidad por defecto.
Objetivos
-
Rote el token de autenticación de Oracle Cloud Infrastructure (OCI), la clave de API, la clave secreta de cliente y la contraseña de la consola de OCI mediante la automatización solucionando el problema de Oracle Cloud Guard. Los siguientes problemas de Oracle Cloud Guard se utilizan para la rotación automática de credenciales de OCI IAM.
- La clave de API es demasiado antigua
- El token de autenticación de IAM es demasiado antiguo
- La clave secreta de cliente de IAM es demasiado antigua
- La contraseña es demasiado antigua
Requisitos
El administrador de OCI IAM debe crear:
-
Grupo dinámico y políticas para que OCI Functions llame, solucione el problema y envíe notificaciones por correo electrónico.
-
Grupo dinámico: cree un grupo dinámico para el compartimento de funciones. Para obtener más información, consulte Creación de un Grupo Dinámico.
# 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...'}
-
Políticas: cree políticas para asignar un grupo dinámico para la función. Para obtener más información, consulte Introducción a las políticas.
# 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, grupo y políticas para que el desarrollador cree secretos y despliegue la función.
# 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
-
Tema de OCI Notifications para que el equipo SecOps reciba notificaciones por correo electrónico.
-
Secretos de Oracle Cloud Infrastructure Secrets in Vault para almacenar las credenciales rotadas de OCI IAM creadas por la automatización.
Nota: Asegúrese de haber copiado las credenciales de OCI IAM existentes para los secretos de Oracle Cloud Infrastructure Secrets in Vault antes de ejecutar esta automatización por primera vez.
Tarea 1: Creación y despliegue de OCI Functions
-
Conéctese a la consola de OCI y haga clic en Cloud Shell en la navegación superior.
Nota: También puede utilizar su propia herramienta de IDE para crear y desplegar una función.
-
Cree una función mediante la CLI del proyecto de Fn desde Cloud Shell. Para obtener más información, consulte Creación, despliegue y llamada de una función Hola mundo.
fn init --runtime python <function-name> Example: fn init --runtime python rotatecred-func
-
Cambie el directorio al directorio creado recientemente.
-
Cree una aplicación para desplegar la función con el siguiente comando.
# 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....."]'
-
Copie y pegue el siguiente script en
func.py
sobrescribiendo el contenido existente.# 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"})
-
Actualice
requirements.txt
como se muestra a continuación.fdk>=0.1.59 oci pycryptodomex
-
Ejecute el siguiente comando para desplegar la función.
fn -v deploy --app <app-name> Example: fn -v deploy --app rotatecredapp
-
Ejecute el siguiente comando para agregar la configuración de función para la clave y el valor de configuración.
ons_topic
: utilice el identificador de Oracle Cloud (OCID) del tema de notificación para recibir notificaciones por correo electrónico.
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
Tarea 2: Creación de una Regla de Evento
-
Vaya a la consola de OCI y haga clic en Observación y gestión.
-
En Servicio de eventos, haga clic en Reglas y Crear regla.
-
En la página Crear regla, introduzca el nombre de la regla y la descripción de lo que hace la regla.
-
En la sección Condiciones de regla, introduzca la siguiente información para especificar el tipo de evento y la acción para disparar la función.
- Condición:
Event Type
. - Nombre de servicio:
Cloud Guard
. - Tipo de evento:
Remediated-Problem
. - Nombre de Atributo:
ProblemRecommendation
. - Valores de Atributo:
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
.
En la siguiente imagen se muestra un ejemplo del evento de solución de problemas de Oracle Cloud Guard.
- Condición:
Tarea 3: Solución del problema de Oracle Cloud Guard
-
Vaya a la consola de OCI y haga clic en Identidad y seguridad.
-
En Cloud Guard, haga clic en Problemas.
-
Haga clic en uno de los problemas admitidos para la rotación automática.
-
Haga clic en Marcar como resuelto e introduzca la siguiente información en la sección Comentario según el siguiente formato. Puede agregar información adicional según el proceso de su organización junto con la siguiente información separada por comas (,).
-
La clave secreta de cliente de IAM es demasiado antigua.
accesskey_secret_ocid:<OCID of access key secret>,secretkey_secret_ocid:<OCID of secret key secret>,<additional comments>
-
La clave de API es demasiado antigua.
api_secret_ocid:<OCID of api key secret>,<additional comments>
-
El token de autenticación de IAM es demasiado antiguo.
auth_secret_ocid:<OCID of auth token secret>,<additional comments>
-
La contraseña es demasiado antigua.
Nota:
- No hay información necesaria para incluir en los comentarios de este problema.
- El usuario individual debe restablecer la contraseña haciendo clic en Olvidé la contraseña en la siguiente conexión. El usuario debe tener una dirección de correo electrónico válida para recibir notificaciones de correo electrónico.
-
Tarea 4: Validación de una nueva credencial de OCI IAM y notificación por correo electrónico
Recibirá una notificación por correo electrónico de resolución de problemas con detalles del OCID secreto rotado e información adicional.
Enlaces relacionados
Agradecimientos
-
Autor: Dipesh Kumar Rathod (arquitecto principal de infraestructura en la nube)
-
Contribuyente - Bhanu Prakash Lohumi (ingeniero sénior en la nube, infraestructura)
Más recursos de aprendizaje
Explore otros laboratorios en docs.oracle.com/learn o acceda a más contenido de aprendizaje gratuito en el canal YouTube de Oracle Learning. Además, visite education.oracle.com/learning-explorer para convertirse en Oracle Learning Explorer.
Para obtener documentación sobre el producto, visite Oracle Help Center.
Enable Auto Rotation of Oracle Cloud Infrastructure Identity and Access Management Credentials
F93263-01
February 2024
Copyright © 2024, Oracle and/or its affiliates.