Oracle Cloud Infrastructure API Keys and OCID

As you may have read in the news, CERN is testing some Oracle Cloud services. When a large organisation is using the Cloud Credits, there's a need to control the service resources. This requires automation and then the GUI interface from the Cloud portal is not sufficient. We can control the Oracle Cloud Infrastructure through the REST API, OCI CLI, OCI SDKs, and all those methods require a RSA key for sign-in and some OCI (Oracle Cloud Identifier) to identify the user, the tenant, the compartment, the service,... We also need to know the URL for our Region (the endpoint) and the version of the API. In order to explain how it works, here is a demo I've run on my own OCI tenant (thanks to the Oracle ACE program providing credits to ACE Directors). I've run this example on Windows 10 WSL (the Windows Linux Subsystem which is actually a Ubuntu distribution) in order to check if all components are available from there.

Generate RSA key

I create a directory to store my private key:

root@Franck:~# mkdir ~/.oci
root@Franck:~# openssl genpkey -out ~/.oci/oci_api_key.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048

I have generated a 2048 bits key in PEM format as this is what is required by the Oracle Cloud. You will not be able to upload a smaller key.

Here it is:

root@Franck:~# ls -l ~/.oci/oci_api_key.pem
-rw------- 1 root root 1704 Sep 15 19:20 ~/.oci/oci_api_key.pem

root@Franck:~# cat ~/.oci/oci_api_key.pem

Be careful with it: anyone with it will be able to access to your cloud service, here I obfuscated mine of course. There was an excellent presentation at POUG about Provilege Escalation in the Cloud from Pieter Van Puymbroek (@vanpupi) where he explains that showing this private key is like giving the key of your datacenter to someone with a laptop and a serial cable. Your cloud services have password authentication for login, but they have also a console.

From the generated private key I generate the public key:

root@Franck:~# openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem
writing RSA key

root@Franck:~# cat ~/.oci/oci_api_key_public.pem
-----END PUBLIC KEY-----

This one can be shared publicly. The only thing you can do with it is to give me access to your system.

Upload public key

Before being able to do everything remotely from command line, I have to upload the key and get a fey identifiers from the Web portal. I'm going to my OCI console, from one of the regions I have access to (here EU-Frankfurt-1):

In the SSO login screen, I verify, or change, the "cloud tenant". The tenancy identifies yourself, or your company, which subscribed to the Oracle Cloud. Here is my login screen (where the tenant is my name):



I open the menu on top left, down to "Governance and Administration", open the "Identity" and "Users". The direct URL to it is:

From this list of users, I click on the user I'll use to sign-in through the REST API. In the Resources, I go to "API Keys" and "Add Public Key". This is where I paste the public key copied from above. This allows me to connect to my cloud service, as long as I have read access to the private key which was used to generate this public key.

Here is my user and list of keys:




I'll need the OCID for my user. Here it is fully displayed after I clicked on "Show". I click on "Copy" to get it in the clipboard. I set it as an environment variable in the shell I'll use later for REST API calls:


Key fingerprint

And the REST API sign-on will also identify the key I've uploaded, with its fingerprint, which I also set in my environment:

The key is identified by its fingerprint, displayed once I've added the public key:


With the authUserId and keyFingerprint I can identify myself as long as I also have my private key. I set the path to this private key also in my environment:


Tenant OCID

The users, as well as the services, are all related to a Tenant (the one I selected in the SSO login page) and I'll need to identify it with an OCID.

I open the menu on top left, down to "Governance and Administration", open the "Administration" and then "Tenancy Details". I can also get there when choosing a Region on the top-right because the regions I can access are related to my tenant. The direct url is:

Here again, you can "Show" and "Copy" the OCID. Without clicking on "Show", only the last digits are displayed:



Again, I set it as an environement variable for later usage:


Compartment OCID

One more identifier is required. All services are segregated into compartments within the tenant, for access security reasons. By default the services will be created in the tenant root, which is the default compartment. This is not a good idea for security reasons: you must disign your compartments to isolate the resources. However, for this test, I'll use the tenant root compartment and you can see that its OCID is the same as the tenant OCID:



I'm setting this information in my environment and now I have everything to be able to connect to the services in this container:


Testing with OCI-CURL

In order to quickly test if everything works well, I'll use the oci-curl function explained by Yasin Baskan, Product Manager of Autonomous Data Warehouse cloud service in where the idea is to use the sample function from the documentation. This script example creates a bash function, named "oci-curl", which is doing all the sign-in steps (build the headers that must change every 5 minutes). The example is referenced in the documentation for OCI sign-in and is fully available at

What I am doing here is get it from internet (with curl), remove the UTF-8 Byte Order Mark "M-oM-;M-?" from first line (which I got when doing that from Windows WSL), and remove the lines which define the tenant and user OCIDs and other variables for private key location and public key fingerprint. When setting the environment variables above, I used the same names on purpose, so that I just have to remove the local declaration from the example.

Here, I directly source the output into my current bash process:

source <( \
 curl     \
  | grep -vE "(local tenancyId|local authUserId=|local keyFingerprint|local privateKeyPath=)" \
  | sed -e '1s/^.*#/#/' 

Of course, this is for demo purpose only, on a lab. You should never run a script directly downloaded from internet without looking at it. Even if you trust, are you sure that the DNS entry is correct?

This has created an oci-curl() function in my current shell which takes the endpoint, the method, and the request as arguments. The result is JSON, and then I pipe the result to JQ to have it nicely displayed. Note that within the Windows WSL, which runs Ubuntu 18.04, I had to install it with "add-apt-repository universe ; apt update ; apt install jq"

The next blog post will detail how to use the REST API with this oci-cutl() function. For the moment, I'll just list the services from my Autonomous Data Warehouse (/autonomousDataWarehouses) and Autonomous Transaction Processing (/autonomousDatabases) services (using the Compartment OCID I've set previously):

oci-curl get "/20160918/autonomousDataWarehouses?compartmentId=$compartmentId" | jq
oci-curl get "/20160918/autonomousDatabases?compartmentId=$compartmentId" | jq

The result, which validates that all the sign-in stuff is ok:



My services are named ADWC and ATP and are both stopped here. All information is available. The next post will show how to automate the start/stop of the services.



The comments are closed on this post, but do not hesitate to give feedback, comment or questions on Twitter (@FranckPachot)