Movatterモバイル変換


[0]ホーム

URL:


Oracle Cloud Infrastructure Documentation


Skip to main content

Accessing Other Oracle Cloud Infrastructure Resources from Running Functions

Find out how to access other Oracle Cloud Infrastructure resources from running functions deployed to OCI Functions.

When a function you've deployed to OCI Functions is running, it can access other Oracle Cloud Infrastructure resources. For example:

  • You might want a function to get a list of VCNs from the Networking service.
  • You might want a function to read data from an Object Storage bucket, perform some operation on the data, and then write the modified data back to the Object Storage bucket.

To enable a function to access another Oracle Cloud Infrastructure resource, you have to include the function in a dynamic group, and then create a policy to grant the dynamic group access to that resource. For more information about dynamic groups, including the permissions required to create them, seeManaging Dynamic Groups.

Having set up the policy and the dynamic group, you can then include a call to a 'resource principal provider' in your function code. The resource principal provider uses a resource provider session token (RPST) that enables the function to authenticate itself with other Oracle Cloud Infrastructure services. The token is only valid for the resources to which the dynamic group has been granted access.

Note also that the token is cached for 15 minutes. So if you change the policy or the dynamic group, you will have to wait for 15 minutes to see the effect of your changes.

We recommend that you use the resource principal provider included in the Oracle Cloud Infrastructure SDK. However, you might be writing a function in a language that the Oracle Cloud Infrastructure SDK does not support. Or you might simply not want to use the Oracle Cloud Infrastructure SDK. In either case, you can write your own custom resource principal provider to enable a function to authenticate itself with other Oracle Cloud Infrastructure services, using files and environment variables in the container in which the function is executing.

Using the Console

To enable a running function to access other Oracle Cloud Infrastructure resources:

  1. Log in to the Console and create a new dynamic group:

    1. Open thenavigation menu  and selectIdentity & Security. UnderIdentity, selectDomains. UnderIdentity domain, selectDynamic groups.
    2. Follow the instructions inTo create a dynamic group, and give the dynamic group a name (for example,acme-func-dyn-grp).
    3. When specifying a rule for the dynamic group, consider the following examples:

      • If you want all functions in a compartment to be able to access a resource, enter a rule similar to the following that adds all functions in the compartment with the specified compartment OCID to the dynamic group:

        ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaaaa23______smwa'}
      • If you want a specific function to be able to access a resource, enter a rule similar to the following that adds the function with the specified OCID to the dynamic group:

        resource.id = 'ocid1.fnfunc.oc1.iad.aaaaaaaaacq______dnya'
      • If you want all functions with a specific defined tag to be able to access a resource, enter a rule similar to the following that adds all functions with the defined tag to the dynamic group :

        ALL {resource.type = 'fnfunc', tag.department.operations.value = '45'}

        Note that free-form tags are not supported. For more information about tagging, seeResource Tags.

    4. SelectCreate Dynamic Group.

    Having created a dynamic group that includes the function, you can now create a policy to give the dynamic group access to the required Oracle Cloud Infrastructure resource.

  2. Create a new policy:

    1. Open thenavigation menu  and selectIdentity & Security. UnderIdentity, selectPolicies.
    2. Follow the instructions inTo create a policy, and give the policy a name (for example,acme-func-dyn-grp-policy).
    3. When specifying a policy statement, consider the following examples:

      • If you want functions in theacme-func-dyn-grp to be able to get a list of all the VCNs in the tenancy, enter a rule similar to the following:

        allow dynamic-group acme-func-dyn-grp to inspect vcns in tenancy
      • If you want functions in theacme-func-dyn-grp to be able to read and write to a particular Object Storage bucket, enter a rule similar to the following:

        allow dynamic-group acme-func-dyn-grp to manage objects in compartment acme-storage-compartment where all {target.bucket.name='acme-functions-bucket'}
      • If you want functions in theacme-func-dyn-grp to be able to read and write to all resources in a compartment, enter a rule similar to the following:

        allow dynamic-group acme-func-dyn-grp to manage all-resources in compartment acme-storage-compartment
    4. SelectCreate to create the new policy.
  3. Include a resource principal provider in the function code to enable the function to authenticate with other Oracle Cloud Infrastructure services. See:

    For a sample Java function, seeFunction that returns the list of instances in the calling Compartment in theOCI Functions samples repository on GitHub.

Example: Adding the Oracle Resource Principal Provider to a Python Function to Get a List of VCNs from the Networking Service

Having added a function to a dynamic group, and created a policy that allows the dynamic group to list the VCNs in the tenancy, you could include code similar to the following example to get a list of VCNs from the Networking service. This example uses the Oracle resource principal provider to extract credentials from the RPST token.

import ioimport jsonfrom fdk import responseimport ocidef handler(ctx, data: io.BytesIO=None):    signer = oci.auth.signers.get_resource_principals_signer()    resp = do(signer)    return response.Response(ctx,        response_data=json.dumps(resp),        headers={"Content-Type": "application/json"} )def do(signer):    # List VCNs --------------------------------------------------------    client = oci.core.VirtualNetworkClient({}, signer=signer)    try:        vcns = client.list_vcns(signer.compartment_id)        vcns = [[v.id, v.display_name] for v in vcns.data]    except Exception as e:        vcns = str(e)    return {"vcns": vcns, }

Example: Adding a Custom Resource Principal Provider to a Function

We recommend that you use the resource principal provider included in the Oracle Cloud Infrastructure SDK. However, you might be writing a function in a language that the Oracle Cloud Infrastructure SDK does not support. Or you might simply not want to use the Oracle Cloud Infrastructure SDK. In either case, you can write your own custom resource principal provider to enable a function to authenticate itself with other Oracle Cloud Infrastructure services, using files and environment variables in the container in which the function is executing.

The container in which a function executes includes a directory tree that holds Oracle Cloud Infrastructure compatible credentials, specifically:

The following environment variables are set inside the container in which the function executes:

  • OCI_RESOURCE_PRINCIPAL_VERSION, containing the value2.2.
  • OCI_RESOURCE_PRINCIPAL_RPST, containing the absolute path to therpst file (including the filename).
  • OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM, containing the absolute path to theprivate.pem file (including the filename).
  • OCI_RESOURCE_PRINCIPAL_REGION, containing the region identifier in which the function is deployed (for example,us-phoenix-1).

To enable a function to access another Oracle Cloud Infrastructure service, add code to the function so that it can authenticate itself with the other resource:

  1. Add code that loads the RPST token from the path in the OCI_RESOURCE_PRINCIPAL_RPST environment variable.
  2. Add code that loads the private key from the path in the OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM environment variable.

  3. Add code that uses the RPST token and the private key to create an Oracle Cloud Infrastructure request signature (seeRequest Signatures).

  4. Add code that constructs the request to the other Oracle Cloud Infrastructure resource.

    If necessary, you can identify:

    • The endpoints of other Oracle Cloud Infrastructure services in the same (local) region as the function, using the region identifier in the OCI_RESOURCE_PRINCIPAL_REGION environment variable.
    • The function's host tenancy and compartment, using theres_tenant andres_compartment claims in the RPST token.

For example, the sample Python function below includes a custom resource principal provider that extracts credentials from the RPST token. It then submits a GET request to the IAM API's getTenancy operation to return the OCID of the function's tenancy.

#!/usr/bin/env python3import base64import email.utilsimport hashlibimport httpsig_cffi.signimport jsonimport loggingimport os.pathimport reimport requests.authimport urllib.parseLOG = logging.getLogger(__name__)# The following class is derived from the Python section in https://docs.cloud.oracle.com/iaas/Content/API/Concepts/signingrequests.htmclass SignedRequestAuth(requests.auth.AuthBase):    """A requests auth instance that can be reused across requests"""    generic_headers = [        "date",        "(request-target)",        "host"    ]    body_headers = [        "content-length",        "content-type",        "x-content-sha256",    ]    required_headers = {        "get": generic_headers,        "head": generic_headers,        "delete": generic_headers,        "put": generic_headers + body_headers,        "post": generic_headers + body_headers,    }    def __init__(self, key_id, private_key):        # Build a httpsig_cffi.requests_auth.HTTPSignatureAuth for each        # HTTP method's required headers        self.signers = {}        for method, headers in self.required_headers.items():            signer = httpsig_cffi.sign.HeaderSigner(                key_id=key_id, secret=private_key,                algorithm="rsa-sha256", headers=headers[:])            use_host = "host" in headers            self.signers[method] = (signer, use_host)    def inject_missing_headers(self, request, sign_body):        # Inject date, content-type, and host if missing        request.headers.setdefault(            "date", email.utils.formatdate(usegmt=True))        request.headers.setdefault("content-type", "application/json")        request.headers.setdefault(            "host", urllib.parse.urlparse(request.url).netloc)        # Requests with a body need to send content-type,        # content-length, and x-content-sha256        if sign_body:            body = request.body or ""            if "x-content-sha256" not in request.headers:                m = hashlib.sha256(body.encode("utf-8"))                base64digest = base64.b64encode(m.digest())                base64string = base64digest.decode("utf-8")                request.headers["x-content-sha256"] = base64string            request.headers.setdefault("content-length", len(body))    def __call__(self, request):        verb = request.method.lower()        # nothing to sign for options        if verb == "options":            return request        signer, use_host = self.signers.get(verb, (None, None))        if signer is None:            raise ValueError(                "Don't know how to sign request verb {}".format(verb))        # Inject body headers for put/post requests, date for all requests        sign_body = verb in ["put", "post"]        self.inject_missing_headers(request, sign_body=sign_body)        if use_host:            host = urllib.parse.urlparse(request.url).netloc        else:            host = None        signed_headers = signer.sign(            request.headers, host=host,            method=request.method, path=request.path_url)        request.headers.update(signed_headers)        return requestdef rp_auther():    if os.environ['OCI_RESOURCE_PRINCIPAL_VERSION'] != "2.2":        raise EnvironmentError('{} must be set to the value "2.2"'.format('OCI_RESOURCE_PRINCIPAL_VERSION'))    rpst = os.environ['OCI_RESOURCE_PRINCIPAL_RPST']    if os.path.isabs(rpst):        with open(rpst) as f:            rpst = f.read()    private_key = os.environ['OCI_RESOURCE_PRINCIPAL_PRIVATE_PEM']    if os.path.isabs(private_key):        with open(private_key) as f:            private_key = f.read()    return get_claims(rpst), SignedRequestAuth('ST${}'.format(rpst), private_key)def get_claims(rpst):    """Parse an RPST as a JWT; return a dictionary of claims    The claims that are important are: sub, res_compartment, and res_tenant.    These carry the resource OCID together with its location.    """    s = rpst.split('.')[1]    s += "=" * ((4 - len(s) % 4) % 4)  # Pad to a multiple of 4 characters    return json.loads(base64.b64decode(s).decode('utf-8'))# Use RP credentials to make a requestregion = os.environ['OCI_RESOURCE_PRINCIPAL_REGION']claims, rp_auth = rp_auther()response = requests.get("https://identity.{}.oraclecloud.com/20160918/tenancies/{}".format(region, claims['res_tenant']), auth=rp_auth)print(response.json())

[8]ページ先頭

©2009-2025 Movatter.jp