An overview to Oracle Cloud's Identity Access and Management policies–syntax and usage
Oracle Cloud's IAM policies allow you granular control over who can access and manage resources in the cloud, using groups of users and resources to efficiently manage access security inside a complex online environment.
⚡️ Quick guide: resource policies
In general, the policies for most resources can be found here under Detailed Service Policy Reference.
Not all resources are here. For example, Nosql, OSMH, OSMS, db-backups, databases, WAF... are not included and you'll have to find them manually.
💠 The syntax
See the following default policy that comes with every tenancy:
allow group Administrators to manage all-resources in tenancy
As can be seen in the example before, all simple* OCI policies follow the non-case-sensitive pattern:
🔹 For OCI user accounts:
allow group <domain>/<group name> to <verb> <resource> in <compartment>
🔹 For instance and resource principals:
allow dynamic-group <domain>/<dynamic group name> to <verb> <resource> in <location> [where <condition>]
*There are some complex exceptions to replace Allow with Endorse, Admit, and Define, but we won't get into that here. There is no Deny in OCI policies.
Briefly explaining the components before we get deeper:
Section | Meaning |
---|---|
group type | The type of IAM principal set this policy applies to--either group for OCI user accounts or dynamic-group for OCI resources |
domain | The IAM Domain of the group. If you're in the Default domain (most of the case), the name of the domain can be cimply left out |
group name | The name (or ID) of the group, e.g., Group-A
|
verb | The level of control of the resource, e.g., manage , {INSTANCE_LAUNCH}
|
resource | The type of resource, e.g., instances , virtual-network-family
|
Location | The name (or ID) of the compartment where the policy applies |
conditions | The conditions this policy applies in, if any |
Now let's dive more into each component:
1️⃣ Group Type
🔹 Simple user groups
Looking at the default administrator policy, we have:
allow group Administrators to manage all-resources in tenancy
This is the simplest policy you have, with the group type group
signifying that the group this policy applies to is a regular OCI users group. In this case, the tenancy administrators.
🔹 Multiple user groups
We can make additional groups such as Group A and Group B in the default identity domain and assign policies to those groups, individually or in combination:
allow group 'Group A', 'Group B' to inspect all-resources in tenancy
Note that the quotes ''
are needed here since there is a space in the group name. Both groups must be of the same type 'group' for this concise statement to work.
🔹 All users and service
To have your policy only be applied to any users and OCI services, use any-user
or any-group
:
allow any-user to inspect compartments in tenancy
I find the below list to be helpful as a baseline when providing general necessary read access for all users to function:
allow any-user to inspect tenancies in tenancy
allow any-user to inspect compartments in tenancy
allow any-user to inspect instances in tenancy where request.operation = 'ListShapes'
allow any-user to read announcements in tenancy
allow any-user to read app-catalog-listing in tenancy
allow any-user to read tag-namespaces in tenancy
allow any-user to read objectstorage-namespaces in tenancy
allow any-user to use cloud-shell in tenancy
allow any-user to use cloud-shell-public-network in tenancy
allow any-user to manage objectstorage-namespaces in tenancy where any { request.operation='GetNamespace', request.operation='GetNamespaceMetadata' }
🔹 Resource and Instance Principals
If the policy is meant to apply to an OCI resource or instance principals--like a group of instances--you will use dynamic-group
instead:
allow dynamic-group compt1-instances to inspect all-resources in tenancy
This is similar to AWS EC2 roles, which only work for internal resources. This is more secure than creating an OCI user account that may be accessed externally.
🔹 Group IDs instead of names
Instead of names, we can also use group OCIDs instead:
allow group id 'ocid1.group.oc1..aaaaaagfnrkyzjuwvrgjjirxmhgurao', 'ocid1.group.oc1..aaaaaagfnrkyzjuwvrgjjirxmhgurap' to inspect all-resources in tenancy
allow dynamic-group id 'ocid1.dynamicgroup.oc1..aaaaaagfnrkyzjuwvrgjjirxmhgurao', 'ocid1.dynamicgroup.oc1..aaaaaagfnrkyzjuwvrgjjirxmhgurap' to inspect all-resources in tenancy
🔹 Services
The policy can also allow a specific internal OCI resource to access other OCI resources. For example,
allow service cloudguard to read virtual-network-family in tenancy
allows the Cloud Guard resource to read your networking resources to identify misconfiguration.
Following a default-deny paradigm, no OCI service has access to manage any other OCI services, including the ones storing customer data.
Some services don't use the group type service
but instead use the more general any-user
type with exceptions carved out to identify the service.
This policy for example, allows the Virtual Network Path Analyzer service to read your VM instances:
allow any-user to read instances in tenancy where ALL { request.principal.type = 'vnpa-service' }
2️⃣ Domain
If the group is not in the Default
domain, you will have to specify the domain. Again, quotes are necessary if there is a space in the domain name:
allow group FederatedDomain/'Group A', FederatedDomain/'Group B' to inspect all-resources in tenancy
3️⃣ Group name
Explained above.
4️⃣ Verb
Let us start with Verbs.
A Verb can either be, in decreasing order of privilege:
Verb | General function |
---|---|
manage | Full access to resource |
use | Allows to update the resource, but not create or delete |
read | Get detailed information on a resource |
inspect | List a collection of resources without detailed information |
🔹 Simple Example
If you want to allow a group to update the details of a WAF like changing its name, but not delete anything, you would write the following policy:
allow group GroupA to use web-app-firewall in compartment compartmentA
🔹 Granular Permissions
To discuss the Verb component, we first have to understand the difference between Verbs and Permissions.
A Verb represents a collection of policy Permissions. These permissions are spelled in UPPER_CASE and represent the granular policy permission that form the building blocks of the Verb.
In this example below involving the load-balancers
resource, we see that inspect
represents the LOAD_BALANCER_INSPECT
permission only. And use
represents the combination of LOAD_BALANCER_INSPECT
+ LOAD_BALANCER_READ
+ LOAD_BALANCER_UPDATE
+ LOAD_BALANCER_MOVE
.
We can write the policy statement using either the more general Verb or the more specific Permission, e.g., to allow the user to update load balancer details:
allow group groupA to use load-balancers in compartment compA
allow group groupA to {LOAD_BALANCER_UPDATE} load-balancers in compartment compA
🔹 Verbs vs Permissions vs APIs
Diving deeper, we introduce another term within this component: API
. An example is CreateSecret
. Spelled in PascalCase.
The API
is simply the name of the specific API call that performs the operation in the Oracle Cloud tenancy when you click on a button in the console UI, in a CLI command, or some other API calling method.
🔶 For example:
- Listing the vault secrets in a compartment ➡️
ListSecrets
(Doc) - Creating a new vault secret ➡️
CreateSecret
(Doc).
To perform an API call, you need to be granted specific granular Permissions, which must be specified directly in the policy statement (e.g., SECRET_INSPECT
) or using a Verb which contains the needed granular Permissions (e.g., inspect secrets
).
We see below from the Details for Vault, Key Management, and Secrets page on the relationship between Verbs, Permissions, and APIs.
🔶 We notice:
- Verbs are a collection of Permissions
- Permissions allow you to call specific APIs
- At times, you need to be granted multiple Permissions to call some APIs, like how both SECRET_UPDATE and SECRET_MOVE is needed for the
ChangeSecretCompartment
API call - At times, you need multiple Permissions of different resources to call some APIs, like how
CreateSecret
need the permissionsSECRET_CREATE
anduse vaults
(specifically,VAULT_CREATE_SECRET
).
We see the original page of the Details for Vault, Key Management, and Secrets describing the relationship below:
I recommend using Permissions for granular permissions and the verbs inspect, read, use, manage for more general permissions (easier). Operations should be reserved since they relate more to the actual API function names.
🔶 For example, these four policies are approximately similar:
allow group logAdmins to inspect log-groups in compartment comptA
allow group logAdmins to manage all-resources in compartment comptA where all { request.permission = /LOG_GROUP_*/, request.operation = /List*/ }
allow group logAdmins to manage all-resources in compartment comptA where all { request.permission = 'LOG_GROUP_INSPECT' }
allow group logAdmins to manage all-resources in compartment comptA where any { request.operation = 'ListLogGroups', request.operation = 'ListLogs' }
5️⃣ Resource
The resource name can refer to either:
- an aggregate resource type (e.g.,
instance-family
) - an individual resource type (e.g.,
instances
)
The aggregate resource type covers multiple individual resource types like the instance example below:
Source: Details for the Core Services
6️⃣ Location
The final mandatory part of an OCI policy determines in which compartment the policy applies to.
OCI policies cascade in the compartments they are declared for. If a policy is declared for a compartment, that compartment and all its descendant children compartments are included.
🔹 tenancy (all compartments)
This policy allows the administrators to manage all resources in the tenancy, i.e., the root compartment and all its descendant compartments:
allow group Administrators to manage all-resources in tenancy
🔹 current compartment and its children
If you are declaring a policy in compartment compA and want the policy to also affect compartment compA, you would write the policy to affect compartment compA:
allow group groupA to manage load-balancers in compartment compA
🔹 current compartment's children
If you are declaring a policy in compartment compA and want the policy to only affect one of compA's children (call it compB) and its descendants, but not compA itself, you would write the policy to affect compartment compB:
allow group groupA to manage load-balancers in compartment compB
🔹 nested compartment
Say the compartment hierarchy goes like this: root > compA > compB > compC > compD.
You are declaring a policy in compartment compA and want the policy to only affect compC and all its descendants. To accomplish this, you would use the colon :
to specify the final compartment name:
allow group groupA to manage load-balancers in compartment compB:compC:compD
🔹 compartment ID
And finally, you can declare the compartment OCID in lieu of a compartment name. This also has the added benefit of not having to nest the compartment hierarchy as above:
allow group groupA to manage load-balancers in compartment id ocid1.compartment.oc1..aaaaaxxxxxxx
7️⃣ Conditions
Last, you can add restrictions and conditions to your policies to restrict when it applies.
🔹 Simple example
For a simple example, this policy allows the group to read everything in the tenancy but not secret contents in the vaults:
allow group groupA to read all-resources in tenancy where request.permission != 'SECRET_BUNDLE_READ'
🔹 Multiple conditions
You can use any
and all
to combine different conditions to create flexible policies:
allow any-user to read all-resources in tenancy where all { request.principal.group.tag.user_ts.user_role='auditors', request.permission != 'SECRET_BUNDLE_READ' }
allow group groupA to manage all-resources in compA where any {target.compartment.name='compB', target.compartment.name='compC'}
allow group comptA-admins to manage all-resources in compartment comptA where all { request.region = 'IAD', request.operation != 'CreateVault', request.permission != /POLICY*/, any { request.operation = /Create*/, request.operation = /Update*/, request.operation = /List*/, request.operation = /Get*/} }
🔹 Patterns
If not a strict string, you can use patterns like /hr*/
to create general conditions. See Policy Syntax
Allow group GroupAdmins to manage groups in tenancy where all {target.group.name=/A-*/, target.group.name!='A-Admins'}
Some exception variables are general and apply to all policies. See here for general variable for policies.
We can give some examples here:
🔹 tags
This policy allows Group A to manage all resources in a compartment that has the defined tag 'TagNamespaceA.editable = yes'. See Tags and Tag Namespace Concepts.
allow group 'FederatedDomain'/'Group A' to read all-resources in compartment compartmentA where all target.resource.tag.TagNamespaceA.editable = 'yes'
Special notes about tags
To allow others to add or remove tags on a specific resource, simply allow them to use the resource:
allow group groupA to use instances in compartment comptA
To allow others to add or delete tags to the tag namespace, use this policy:
allow any-user to use tag-namespaces in tenancy where target.tag-namespace.name='new-tag-namespace'
🔹 compartment
Using the compartment ID or name, the user can restrict the policy to only apply to resources in a specific compartment. While you can do that using the location variable as stated above, this allows you to further restrict the policy to only one compartment rather than including its descendants. See Details for IAM with Identity Domains.
allow group groupA to manage all-resources in compA where target.compartment.name = 'compB'
allow group groupA to {API_GATEWAY_READ} in compA where target.compartment.id = 'ocid1.compartment.oc1..ihyqrpbgzfhfrpggjqadirfcaihyqrpbgzfhfrpggjqadirfca'
🔹 region
If your tenancy has been subscribed to multiple regions but you only want to restrict your users to only certain regions, use request.region
:
allow dynamic-group 'Federated'/'dgrpA' to {VAULT_INSPECT, VAULT_READ} in compartment compB where request.region = 'iad'
Reminder: iad is the airport code for Washington Dulles Airport, which is the short form for the Ashburn Eastern US region in OCI
🔹 network source IP
Here, you restrict who is granted permission within that policy through their origin IP address. Create a network source containing a list of whitelisted IP addresses and specify the policy to only allow for that network source.
See Allowing Access to Resources from Only Specified IP Addresses.
allow group CorporateUsers to manage object-family in tenancy where request.networkSource.name='corpnet'
🔹 user
While it is recommended to apply a policy by the group rather than the individual user, you can restrict the policy by the requesting user ID:
allow group groupA to manage compartments where request.user.id = 'ocid1.user.oc1..aaaaaaxxx'
🔹 group tag
Restrict who this policy applies to by the tag of their group.
allow any-user to {VAULT_INSPECT, VAULT_READ, VAULT_CREATE_SECRET} in compartment open-vault where request.principal.group.tag.users_ts.user_role='admin-users'
Some resources allow you to further restrict policies using a relevant resource specifier. For example,
🔹 bucket / object name
Specific to the Object Storage OCI resource, you can craft policies that only allow the group to access a certain groups of bucket and objects according to their names (Policy Builder Policy Templates):
allow group test-group to manage objects in tenancy where target.bucket.name = 'test-bucket'
allow group test-group to manage objects in tenancy where target.object.name = 'prod/*'
You can also use the tags on the buckets—though we have previously discussed how to use tags in policies generally:
Allow group ObjectWriters to read buckets in compartment ABC
Allow group ObjectWriters to manage objects in compartment ABC where target.bucket.tag.MyTagNamespace.TagKey='MyTagValue'
🔹 vault secret name
Specific to the Vault & Key Management Services resource, we can use target.secret.name
to narrow down the specific secret name the user will have access to (Details for Vault, Key Management, and Secrets):
allow group SpecialSecretReaders to read secret-bundles in compA where target.secret.name = 'secret001'
Note: the resources secrets
and secret-bundles
represent two different things. The first allows you to read the metadata of the secret
object, while the second allows you to decrypt and read the contents.
References
Safe harbor statement
The information provided on this channel/article/story is solely intended for informational purposes and cannot be used as a part of any contractual agreement. The content does not guarantee the delivery of any material, code, or functionality, and should not be the sole basis for making purchasing decisions. The postings on this site are my own and do not necessarily reflect the views or work of Oracle or Mythics, LLC.
This work is licensed under a Creative Commons Attribution 4.0 International License.
Top comments (0)