Note:
- This tutorial requires access to Oracle Cloud. To sign up for a free account, see Get started with Oracle Cloud Infrastructure Free Tier.
- It uses example values for Oracle Cloud Infrastructure credentials, tenancy, and compartments. When completing your lab, substitute these values with ones specific to your cloud environment.
Automate the Instance Metadata Service update to version 2 only for OCI Compute Instances using Event Rules and Python Functions
Introduction
Ensuring security and consistency across cloud environments is a priority for modern enterprises. In Oracle Cloud Infrastructure (OCI), the Instance Metadata Service (IMDS) provides critical instance-specific information, and enforcing its use of version 2 (IMDSv2) enhances security by requiring session-based authentication. Automating the upgrade to IMDSv2 across all OCI Compute instances is an effective way to maintain this security standard while reducing manual overhead.
This tutorial demonstrates how to build an automated, event-driven workflow using OCI Events Service rules and OCI Functions to enforce the IMDSv2 update. By leveraging Python-based automation, you will create and configure the necessary OCI resources - such as dynamic groups, event rules, and serverless functions to seamlessly ensure compliance with this enhanced security protocol.
Objectives
- Automating the update of IMDS to version 2 in OCI ensures better security and control over instance metadata access. By using event rules and Python functions, you can create an automated workflow that enforces this update whenever new instances are launched. This approach simplifies the management of instance metadata settings while maintaining consistency across your cloud environment.
Prerequisites
-
Oracle Cloud Infrastructure Command Line Interface (OCI CLI) and Python Software Development Kit (SDK): Install and configure OCI CLI and Python SDK for programmatic access.
-
Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) Policies: Ensure the required OCI IAM policies are in place to manage dynamic groups, functions, and event rules.
-
Compartment Oracle Cloud Identifier (OCID): Obtain the OCID of the compartment where resources will be deployed.
-
Python Environment: Set up Python with the OCI library installed (
pip install oci
). -
OCI Functions Setup: Ensure OCI Functions is enabled in your tenancy and a Docker environment is configured for deployment.
-
User Permissions: Ensure you have permissions to create and manage OCI resources.
Task 1: Create a Dynamic Group
Define a dynamic group to allow the function to access the target instances. In order to use other OCI services, your function must be part of a dynamic group.
ALL {resource.type = 'fnfunc'}
When specifying the matching rules, we suggest matching all functions in a compartment with:
ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'}
Task 2: Define OCI IAM Policies
Create a new policy that allows the dynamic group to manage compute instances. We will grant manage access to instances in the specific compartment.
Allow dynamic-group dmg-for-functions to manage instance-family in compartment Compartment-Name
Allow dynamic-group dmg-for-functions to manage functions-family in compartment Compartment-Name
Allow dynamic-group dmg-for-functions to use virtual-network-family in compartment Compartment-Name
Allow dynamic-group dmg-for-functions to manage instances in compartment Compartment-Name
Allow dynamic-group dmg-for-functions to read repos in compartment Compartment-Name
Task 3: Create and Deploy the OCI Functions
Create, deploy, and invoke the function for IMDS update.
-
Create an application in the OCI Console.
Log in to the OCI Console, navigate to Developer Services, Functions and click Applications. Select the appropriate region for OCI Functions and click Create Application.
-
Set up the environment for function deployment, perform the following setup on your OCI Cloud Shell or OCI Compute instance (running Oracle Linux 8) or any system where you plan to create and deploy the function.
-
Install the following resources: Installing the CLI, Install Fn Project CLI and Install Oracle Cloud Infrastructure Python SDK.
-
Follow the detailed setup guide in the OCI Functions QuickStart on an OCI Compute Instance to prepare the environment. This preparation ensures your environment is ready for creating, deploying, and managing OCI Functions seamlessly.
Note: Verify that you have a repository created in the OCI Registry for your function images.
-
-
Log in to the OCI Cloud Shell or OCI Compute instance and access the OCI Cloud Shell or your OCI Compute instance where you will be creating the function. Set the context for the OCI Functions CLI to specify the region where the function will be deployed.
fn use context <region-name> Replace <region-name> with the appropriate region (e.g., ap-hyderabad-1).
-
Update context with compartment ID. Run the following command to set the compartment where the application will reside.
fn update context oracle.compartment-id <compartment-ocid>
-
Set up the OCI Registry. Enter a unique repository name prefix to distinguish your function images. Run the following command to update the registry.
fn update context registry <region-key>.ocir.io/<tenancy-namespace>/<repo-name-prefix> Example: ap-hyderabad-1.ocir.io/namespace/prefix.
-
Generate an auth token from the OCI Console under your user profile and run the following command to log in to the container registry using the auth token.
docker login -u '<tenancy-namespace>/<user-id>' <region-key>.ocir.io
-
Confirm that the application is correctly set up by listing applications. Run the following command to list the application.
fn list apps
-
Create a new function named
imdsupdate
using the Python runtime and initialize the function.fn init --runtime python imdsupdate
-
Run the following command to navigate to the created directory.
cd imdsupdate
-
Run the
ls
command to list the files generated.ls
Task 4: Update the Python Function Code
-
Open and edit the generated Python file (for example,
func.py
) in the directory and add the following python code to function file for the logic.import io import json import logging from fdk import response import oci def handler(ctx, data: io.BytesIO = None): try: # Authenticate using Instance Principals signer = oci.auth.signers.get_resource_principals_signer() body = json.loads(data.getvalue()) logging.getLogger().info("Event body: " + str(body)) # Extract Required Details From Event Rule instance_id = body["data"]["resourceId"] # Instance OCID action_type = body["eventType"] logging.getLogger().info("Action type: " + action_type) # Proceed only if instance creation event if action_type == "com.oraclecloud.computeapi.launchinstance.end": compute_client = oci.core.ComputeClient(config={}, signer=signer) update_instance_imds(compute_client, instance_id) except (Exception, ValueError) as ex: logging.getLogger().error("Error: " + str(ex)) return response.Response( ctx, response_data=json.dumps({"message": "Error: " + str(ex)}), headers={"Content-Type": "application/json"}, ) return response.Response( ctx, response_data=json.dumps({"message": "Function executed successfully"}), headers={"Content-Type": "application/json"}, ) def update_instance_imds(compute_client, instance_id): """ Updates the instance metadata service (IMDS) configuration to disable legacy endpoints. """ try: # Fetch instance details instance_details = compute_client.get_instance(instance_id).data # Update instance configuration update_details = oci.core.models.UpdateInstanceDetails( instance_options=oci.core.models.InstanceOptions( are_legacy_imds_endpoints_disabled=True # Disable legacy endpoints ) ) response = compute_client.update_instance(instance_id, update_details) logging.getLogger().info( f"Successfully updated IMDS for instance {instance_id}: {response.data}" ) except Exception as ex: logging.getLogger().error("Failed to update IMDS: " + str(ex)) raise
-
Update the
requirements.txt
file.fdk>=0.1.86 oci==2.138.0
-
Run the following command to deploy the function to the created application.
fn -v deploy --app <application-name> Example: fn -v deploy --app functionpyth.
These steps ensure the function is created, deployed, and ready to be invoked for automating IMDS version updates in OCI.
Task 5: Define the Event Rule
Use the OCI Events Service to detect when a new OCI Compute instance is created.
To configure event rule, enter the following information.
- Event Source: Select Compute Instance.
- Condition: Select Event Type is Instance – Launch End.
- Action: Select Trigger a Function, enter functions, function compartment, functions application and the function to trigger which you created in Task 4.
Task 6: Validate the Instance IMDS Value
Launch a new instance to trigger the event rule and verify the instance metadata service configuration. Once the Virtual Machine (VM) creation is completed, it will automatically set the IMDS value to version 2 only.
These configurations are region and compartment specific. If you want to call the same function in a different compartment, then create a event rule in that compartment and set a rule to trigger this function.
By completing these tasks, you will automate the process of updating the IMDS version to v2 for OCI Compute instances in a specific compartment.
Related Links
Acknowledgments
- Author - Akarsha I K (Cloud Architect)
More Learning Resources
Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.
For product documentation, visit Oracle Help Center.
Automate the Instance Metadata Service update to version 2 only for OCI Compute Instances using Event Rules and Python Functions
G24468-01
January 2025