Note:

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

Instance IMDS Update

Prerequisites

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'}

Dynamic Group

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

Policies

Task 3: Create and Deploy the OCI Functions

Create, deploy, and invoke the function for IMDS update.

  1. 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.

    OCI Functions

  2. 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.

  3. 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).
    
  4. 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>
    
  5. 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.
    
  6. 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
    
  7. Confirm that the application is correctly set up by listing applications. Run the following command to list the application.

    fn list apps
    
  8. Create a new function named imdsupdate using the Python runtime and initialize the function.

    fn init --runtime python imdsupdate
    
  9. Run the following command to navigate to the created directory.

    cd imdsupdate
    
  10. Run the ls command to list the files generated.

    ls
    

Task 4: Update the Python Function Code

  1. 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
    
  2. Update the requirements.txt file.

    fdk>=0.1.86
    oci==2.138.0
    
  3. 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.

Function Code Update

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 Rule

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.

Acknowledgments

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.