Raw Requests¶
The Python SDK exposes a custom requests.auth.AuthBase
which you can use to sign non-standard calls.
This can be helpful if you need to make an authenticated request to an alternate endpoint or to an
Oracle Cloud Infrastructure API not yet supported in the SDK.
Creating a Signer¶
The Signer used as part of making raw requests can be either an Instance Principals-based signer or one that uses a user OCID and private key.
Signer with user OCID and private key¶
Constructing a Signer instance requires a few pieces of information. By default, the SDK uses the values in
the config file at ~/.oci/config
. You can manually specify the required fields, or use a config loader
to pull in the values from a file:
from oci.signer import Signer
auth = Signer(
tenancy='ocid1.tenancy.oc1..aaaaaaaa[...]',
user='ocid1.user.oc1..aaaaaaaa[...]',
fingerprint='20:3b:97:13:55:1c:[...]',
private_key_file_location='~/.oci/oci_api_key.pem',
pass_phrase='hunter2' # optional
)
# Or load directly from a file
from oci.config import from_file
config = from_file('~/.oci/config')
auth = Signer(
tenancy=config['tenancy'],
user=config['user'],
fingerprint=config['fingerprint'],
private_key_file_location=config['key_file'],
pass_phrase=config['pass_phrase']
)
Instance Principals-based Signer¶
An Instance Principals-based signer can be created as follows:
import oci
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
To customize timeouts while retrieving certificates from identity, you can now provide a custom retry strategy while creating the signer:
import oci
custom_strategy = oci.retry.RetryStrategyBuilder().add_max_attempts(4).get_retry_strategy()
signer_kwargs = {'retry_strategy': custom_strategy}
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner(**signer_kwargs)
Using the Signer¶
Once you have an instance of the auth handler, simply include it as the auth=
param when using Requests.
import requests
url = 'https://iaas.us-phoenix-1.oraclecloud.com/20160918/instances[...]'
response = requests.get(url, auth=auth)
Remember that the result will come back in its raw form and is not unpacked into a model instance. You will need to handle the (de)serialization yourself.
The following creates a new user by talking to the identity endpoint:
endpoint = 'https://identity.us-phoenix-1.oci.oraclecloud.com/20160918/users/'
body = {
'compartmentId': config['tenancy'], # root compartment
'name': 'TestUser',
'description': 'Created with a raw request'
}
response = requests.post(endpoint, json=body, auth=auth)
response.raise_for_status()
print(response.json()['id'])
Using an Instance Principals-based Signer¶
The Instance Principals-based Signer uses a security token to authenticate calls against Oracle Cloud Infrastructure services. This token has an expiration time and the Signer will automatically handle refreshing the token when it is near expiry. However, it is possible that the security token held by the signer is valid (from an expiration time perspective) but the request fails with a 401 (NotAuthenticated) error because of, for example, changes in the dynamic group that an instance is a part of or the policies applied to that dynamic group.
You can account for this by retrying on a 401. If the request fails with a 401 on a subsequent retry, this may point to other issues and you should not keep retrying in this circumstance. For example:
import oci
import requests
signer = oci.auth.signers.InstancePrincipalsSecurityTokenSigner()
call_attempts = 0
while call_attempts < 2:
# This call is just an example. Provide your own appropriate method (e.g. get() instead of post()), endpoint and body
response = requests.post(endpoint, json=body, auth=signer)
if response.ok:
return response
else:
call_attempts += 1
if response.status_code == 401 and call_attempts < 2:
signer.refresh_security_token()
else:
response.raise_for_status()