Oracle Cloud Infrastructure Documentation

Securing Object Storage

Security Recommendations

Assign least privilege access for IAM users and groups to resource types in object-family, namely buckets and objects. For example, the inspect verb gives least privilege and allows checking whether a bucket exists (HeadBucket) and list buckets in a compartment (ListBucket), while the manage verb gives all permissions. You can craft IAM security policies to give appropriate bucket and object access to various IAM groups. For more information about IAM verbs and permissions for object storage buckets and objects, see Details for Object Storage, Archive Storage, and Data Transfer. For users without IAM credentials, Oracle recommends pre-authenticated requests (PARs) to give time-bound access to objects or buckets.

Public Buckets Security Controls

  • A public bucket allows unauthenticated and anonymous reads to all objects in the bucket. Carefully evaluate the intended use case for public buckets before you enable public buckets. Oracle recommends that you use pre-authenticated requests (PAR) to give bucket or object access(read or write) to users without IAM credentials. Note that buckets are created with no public access by default (with access type set to NoPublicAccess).
  • You can make existing buckets public by updating the bucket access type to ObjectRead or ObjectReadWithoutList". To minimize possibility of existing buckets being made public inadvertently or maliciously, BUCKET_UPDATE permission should be restricted to a minimal set of IAM groups.

Pre-Authenticated Request (PAR)

  • Pre-authenticated requests (PARs) provide a mechanism to provide access to objects stored in buckets, to users who do not have IAM user credentials. In a PAR, an IAM user who has appropriate privileges for accessing objects, can create URLs which grant time-bound read or write access to these objects. For more information about creating PARs, see Using Pre-Authenticated Requests.
  • The creator of a PAR must have PAR_MANAGE IAM permission. Following types of PARs can be created, (a) bucket PAR to allow writes to the bucket, (b) object for reading object, (c) object PAR for writing object, and (d) object PAR to read or write an object. PAR cannot be used to list objects in a bucket.
  • All PAR accesses to a bucket or object are logged in Audit logs
  • Oracle recommends that you note down the PAR URL created. By design, it is not possible to retrieve a forgotten PAR URL. If you forget a PAR URL, you must create a new PAR.

Data Durability

  • To minimize loss of data due to inadvertent deletes by an authorized user or malicious deletes, it is recommended to to give BUCKET_DELETE and OBJECT_DELETE permissions to a minimum possible set of IAM users/groups. DELETE permissions should preferably be given only to tenancy and compartment admins.
  • Write once read many (WORM) compliance requires objects can neither be deleted or modified. This can be achieved by granting OBJECT_CREATE, OBJECT_READ, and OBJECT_INSPECT permissions to an IAM group. Note that we precluded OBJECT_OVERWRITE permission to prevent modifications to existing object, along with OBJECT_DELETE.

Data Encryption

  • All data in object storage is encrypted at rest by using AES-256. Encryption is on by default and cannot be turned off. Each object is encrypted with its encryption key, and the object encryption keys are encrypted with a master encryption key. In addition, customers can use client-side encryption to encrypt objects with their encryption keys before storing them in object store buckets. An available option for customers is to use the S3 compatibility API, along with client-side object encryption support available in AWS SDK for Java. More details on this SDK are available here (link: https://docs.cloud.oracle.com/iaas/Content/Object/Tasks/s3compatibleapi.htm).
  • Data in transit between customer clients (for example, SDKs and CLIs) and object storage public end-points is encrypted with TLS 1.2 by default. FastConnect public peering allows on-premises access to object storage to go over a private circuit, rather than than public internet.

Data Integrity

  • Cryptographic hash using MD5 is provided for all objects uploaded to Object Storage, to verify object data integrity. Oracle recommends that you verify the offline MD5 hash of the object matches the hash value returned by the console or API after the object is uploaded. Oracle Cloud Infrastructure provides the object hash value in base64 encoding. To covert the base64 encoded hash value to hexadecimal, the following command can be used.

    python -c 'print "BASE64-ENCODED-MD5-VALUE".decode("base64").encode("hex")'

    Linux provides md5sum command-line utility to compute MD5 hash value of a file in hexadecimal format.

  • Object Storage service supports multipart uploads for more efficient and resilient uploads, especially for large objects. In multi-part upload, a large object (to be uploaded to Object Storage) is broken up into smaller parts (by specifying part size in MB), and each part is uploaded separately where Object Storage combines all the parts to put together the original object. If any of the parts fail to upload, only those parts need to be retried for upload, and not the entire object which is very efficient. In a multi-part upload, the MD5 hash values are computed for each part, and a MD5 hash computed over all the individual hash values to get the output MD5 value. In order to verify the MD5 value returned for a multi-part upload, we need to follow the same process for offline MD5 hash calculation. A sample script for offline calculation of MD5 hash value for a multi-part upload to Object Storage is available here (link: https://gist.github.com/itemir/f5bc9fded6483cd79c89ebf4ca1cfd30).

Security Policy Examples

In all the examples below, the policies are scoped to a tenancy. However, by specifying a compartment name, they can be scoped down to specific compartment(s) in a tenancy.

Restrict Group Access to Specific Buckets

You can restrict access by a group to a specific bucket by using the specific bucket name (target.bucket.name), regular expression matching (/*name/, /name*/, /*name*/), or defined tags (target.tag.definition.name).

The following is an example of restricting access by groups BucketUsers to a specific bucket.

Allow group BucketUsers to use buckets in tenancy
 where target.bucket.name='BucketFoo'.

You can modify this policy to restrict access by group BucketUsers to all buckets whose names are prefixed with ProjectA_.

Allow group BucketUsers to use buckets in tenancy
 where target.bucket.name=/ProjectA_*/

You can also match for post-fix (/*_ProjectA/), or sub-string (/*ProjectA*/).

Restrict Group Access to Read or Write to Objects in a Specific Bucket

The following example allows listing and reading objects by group BucketUsers from a specific bucket named BucketFoo.

Allow group BucketUsers to read buckets in tenancy
Allow group BucketUsers to manage objects in tenancy
 where all {target.bucket.name='BucketFoo', 
            any {request.permission='OBJECT_INSPECT', 
                 request.permission='OBJECT_READ'}}

The following policy modifies the previous policy to allow listing and writing objects to BucketFoo.

Allow group BucketUsers to read buckets in tenancy 
Allow group BucketUsers to manage objects in tenancy
 where all {target.bucket.name='BucketFoo', 
            any {request.permission='OBJECT_INSPECT', 
                 request.permission='OBJECT_CREATE'}}

You can restrct this policy to read or write access to a set of buckets by using regular expressions or tags rather than a specific bucket.

Prevent Delete of Buckets or Objects

In the following example, the group BucketUsers can perform all actions on buckets and objects except delete.

Allow group BucketUsers to manage objects in tenancy
 where request.permission!='OBJECT_DELETE' 
Allow group BucketUsers to manage buckets in tenancy
 where request.permission!='BUCKET_DELETE'

The following example further restricts deletes from a specific bucket (BucketFoo).

Allow group BucketUsers to manage objects in tenancy
  where any {target.bucket.name!='BucketFoo', 
             all {target.bucket.name='BucketFoo',
                  request.permission!='OBJECT_DELETE'}}

Enable Write Once, Read Many Compliance for Objects

The following policy enables write once, read many (WORM) compliance by removing permissions for group BucketUsers to delete or update objects.

Allow group BucketUsers to manage objects in tenancy
 where any {request.permission='OBJECT_INSPECT', 
            request.permission='OBJECT_READ', 
            request.permission='OBJECT_CREATE'}

The following policy allows for WORM compliance.

Allow group BucketUsers to manage buckets in tenancy
 where any {request.permission='BUCKET_INSPECT', 
            request.permission='BUCKET_READ', 
            request.permission='BUCKET_CREATE', 
            request.permission='PAR_MANAGE'}

Prevent Public Buckets Configuration

As mentioned in previous section, BUCKET_CREATE and BUCKET_UDPATE permissions are required to create public buckets, or update existing buckets to public. Removing these permissions prevents users from creating new or making existing buckets public.

Allow group BucketUsers to manage buckets in tenancy
 where any {request.permission='BUCKET_INSPECT', 
            request.permission='BUCKET_READ', 
            request.permission='PAR_MANAGE'}

Useful CLI Commands

In the examples below, environment variables $NS and $C are set tenancy namespace and compartment OCID, respectively.

List Public Buckets

The following command returns the public access buckets for each bucket in a namespace.

# "public-access-type" of 'NoPublicAccess' indicates a private bucket, and 
# anything else ('ObjectRead') indicates a public bucket 
oci os bucket get -ns $NS --bucket-name $BUCKET_NAME | grep "public-access-type"

List Bucket Pre-authenticated Requests (PARs)

# list all PARs for objects in bucket $BUCKET_NAME 
oci os preauth-request list -ns $NS -bn $BUCKET_NAME